blob: f4f6b661c0e1f6d30bb52e218df7535b24b63cda [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.server.am;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Process;
import android.os.UserHandle;
import android.util.Slog;
import com.android.internal.R;
import com.android.internal.util.ProgressReporter;
import com.android.server.UiThread;
import java.util.List;
/**
* Simple broadcaster that sends {@link Intent#ACTION_PRE_BOOT_COMPLETED} to all
* system apps that register for it. Override {@link #onFinished()} to handle
* when all broadcasts are finished.
*/
public abstract class PreBootBroadcaster extends IIntentReceiver.Stub {
private static final String TAG = "PreBootBroadcaster";
private final ActivityManagerService mService;
private final int mUserId;
private final ProgressReporter mProgress;
private final boolean mQuiet;
private final Intent mIntent;
private final List<ResolveInfo> mTargets;
private int mIndex = 0;
public PreBootBroadcaster(ActivityManagerService service, int userId,
ProgressReporter progress, boolean quiet) {
mService = service;
mUserId = userId;
mProgress = progress;
mQuiet = quiet;
mIntent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
mIntent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE | Intent.FLAG_DEBUG_TRIAGED_MISSING);
mTargets = mService.mContext.getPackageManager().queryBroadcastReceiversAsUser(mIntent,
MATCH_SYSTEM_ONLY, UserHandle.of(userId));
}
public void sendNext() {
if (mIndex >= mTargets.size()) {
mHandler.obtainMessage(MSG_HIDE).sendToTarget();
onFinished();
return;
}
if (!mService.isUserRunning(mUserId, 0)) {
Slog.i(TAG, "User " + mUserId + " is no longer running; skipping remaining receivers");
mHandler.obtainMessage(MSG_HIDE).sendToTarget();
onFinished();
return;
}
if (!mQuiet) {
mHandler.obtainMessage(MSG_SHOW, mTargets.size(), mIndex).sendToTarget();
}
final ResolveInfo ri = mTargets.get(mIndex++);
final ComponentName componentName = ri.activityInfo.getComponentName();
if (mProgress != null) {
final CharSequence label = ri.activityInfo
.loadLabel(mService.mContext.getPackageManager());
mProgress.setProgress(mIndex, mTargets.size(),
mService.mContext.getString(R.string.android_preparing_apk, label));
}
Slog.i(TAG, "Pre-boot of " + componentName.toShortString() + " for user " + mUserId);
EventLogTags.writeAmPreBoot(mUserId, componentName.getPackageName());
mIntent.setComponent(componentName);
mService.broadcastIntentLocked(null, null, mIntent, null, this, 0, null, null, null,
AppOpsManager.OP_NONE, null, true, false, ActivityManagerService.MY_PID,
Process.SYSTEM_UID, mUserId);
}
@Override
public void performReceive(Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, int sendingUser) {
sendNext();
}
private static final int MSG_SHOW = 1;
private static final int MSG_HIDE = 2;
private Handler mHandler = new Handler(UiThread.get().getLooper(), null, true) {
@Override
public void handleMessage(Message msg) {
final Context context = mService.mContext;
final NotificationManager notifManager = context
.getSystemService(NotificationManager.class);
final int max = msg.arg1;
final int index = msg.arg2;
switch (msg.what) {
case MSG_SHOW:
final CharSequence title = context
.getText(R.string.android_upgrading_notification_title);
final Intent intent = new Intent();
intent.setClassName("com.android.settings",
"com.android.settings.HelpTrampoline");
intent.putExtra(Intent.EXTRA_TEXT, "help_url_upgrading");
final PendingIntent contentIntent;
if (context.getPackageManager().resolveActivity(intent, 0) != null) {
contentIntent = PendingIntent.getActivity(context, 0, intent, 0);
} else {
contentIntent = null;
}
final Notification notif = new Notification.Builder(mService.mContext)
.setSmallIcon(R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
.setTicker(title)
.setDefaults(0)
.setPriority(Notification.PRIORITY_MAX)
.setColor(context.getColor(
com.android.internal.R.color.system_notification_accent_color))
.setContentTitle(title)
.setContentIntent(contentIntent)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setProgress(max, index, false)
.build();
notifManager.notifyAsUser(TAG, 0, notif, UserHandle.of(mUserId));
break;
case MSG_HIDE:
notifManager.cancelAsUser(TAG, 0, UserHandle.of(mUserId));
break;
}
}
};
public abstract void onFinished();
}