1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.server.am; 18 19 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; 20 21 import android.app.AppOpsManager; 22 import android.app.Notification; 23 import android.app.NotificationManager; 24 import android.app.PendingIntent; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.IIntentReceiver; 28 import android.content.Intent; 29 import android.content.pm.ResolveInfo; 30 import android.os.Bundle; 31 import android.os.Handler; 32 import android.os.Message; 33 import android.os.Process; 34 import android.os.UserHandle; 35 import android.util.Slog; 36 37 import com.android.internal.R; 38 import com.android.internal.util.ProgressReporter; 39 import com.android.server.UiThread; 40 41 import java.util.List; 42 43 /** 44 * Simple broadcaster that sends {@link Intent#ACTION_PRE_BOOT_COMPLETED} to all 45 * system apps that register for it. Override {@link #onFinished()} to handle 46 * when all broadcasts are finished. 47 */ 48 public abstract class PreBootBroadcaster extends IIntentReceiver.Stub { 49 private static final String TAG = "PreBootBroadcaster"; 50 51 private final ActivityManagerService mService; 52 private final int mUserId; 53 private final ProgressReporter mProgress; 54 private final boolean mQuiet; 55 56 private final Intent mIntent; 57 private final List<ResolveInfo> mTargets; 58 59 private int mIndex = 0; 60 PreBootBroadcaster(ActivityManagerService service, int userId, ProgressReporter progress, boolean quiet)61 public PreBootBroadcaster(ActivityManagerService service, int userId, 62 ProgressReporter progress, boolean quiet) { 63 mService = service; 64 mUserId = userId; 65 mProgress = progress; 66 mQuiet = quiet; 67 68 mIntent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED); 69 mIntent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE | Intent.FLAG_DEBUG_TRIAGED_MISSING); 70 71 mTargets = mService.mContext.getPackageManager().queryBroadcastReceiversAsUser(mIntent, 72 MATCH_SYSTEM_ONLY, UserHandle.of(userId)); 73 } 74 sendNext()75 public void sendNext() { 76 if (mIndex >= mTargets.size()) { 77 mHandler.obtainMessage(MSG_HIDE).sendToTarget(); 78 onFinished(); 79 return; 80 } 81 82 if (!mService.isUserRunning(mUserId, 0)) { 83 Slog.i(TAG, "User " + mUserId + " is no longer running; skipping remaining receivers"); 84 mHandler.obtainMessage(MSG_HIDE).sendToTarget(); 85 onFinished(); 86 return; 87 } 88 89 if (!mQuiet) { 90 mHandler.obtainMessage(MSG_SHOW, mTargets.size(), mIndex).sendToTarget(); 91 } 92 93 final ResolveInfo ri = mTargets.get(mIndex++); 94 final ComponentName componentName = ri.activityInfo.getComponentName(); 95 96 if (mProgress != null) { 97 final CharSequence label = ri.activityInfo 98 .loadLabel(mService.mContext.getPackageManager()); 99 mProgress.setProgress(mIndex, mTargets.size(), 100 mService.mContext.getString(R.string.android_preparing_apk, label)); 101 } 102 103 Slog.i(TAG, "Pre-boot of " + componentName.toShortString() + " for user " + mUserId); 104 EventLogTags.writeAmPreBoot(mUserId, componentName.getPackageName()); 105 106 mIntent.setComponent(componentName); 107 mService.broadcastIntentLocked(null, null, mIntent, null, this, 0, null, null, null, 108 AppOpsManager.OP_NONE, null, true, false, ActivityManagerService.MY_PID, 109 Process.SYSTEM_UID, mUserId); 110 } 111 112 @Override performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser)113 public void performReceive(Intent intent, int resultCode, String data, Bundle extras, 114 boolean ordered, boolean sticky, int sendingUser) { 115 sendNext(); 116 } 117 118 private static final int MSG_SHOW = 1; 119 private static final int MSG_HIDE = 2; 120 121 private Handler mHandler = new Handler(UiThread.get().getLooper(), null, true) { 122 @Override 123 public void handleMessage(Message msg) { 124 final Context context = mService.mContext; 125 final NotificationManager notifManager = context 126 .getSystemService(NotificationManager.class); 127 final int max = msg.arg1; 128 final int index = msg.arg2; 129 130 switch (msg.what) { 131 case MSG_SHOW: 132 final CharSequence title = context 133 .getText(R.string.android_upgrading_notification_title); 134 135 final Intent intent = new Intent(); 136 intent.setClassName("com.android.settings", 137 "com.android.settings.HelpTrampoline"); 138 intent.putExtra(Intent.EXTRA_TEXT, "help_url_upgrading"); 139 140 final PendingIntent contentIntent; 141 if (context.getPackageManager().resolveActivity(intent, 0) != null) { 142 contentIntent = PendingIntent.getActivity(context, 0, intent, 0); 143 } else { 144 contentIntent = null; 145 } 146 147 final Notification notif = new Notification.Builder(mService.mContext) 148 .setSmallIcon(R.drawable.stat_sys_adb) 149 .setWhen(0) 150 .setOngoing(true) 151 .setTicker(title) 152 .setDefaults(0) 153 .setPriority(Notification.PRIORITY_MAX) 154 .setColor(context.getColor( 155 com.android.internal.R.color.system_notification_accent_color)) 156 .setContentTitle(title) 157 .setContentIntent(contentIntent) 158 .setVisibility(Notification.VISIBILITY_PUBLIC) 159 .setProgress(max, index, false) 160 .build(); 161 notifManager.notifyAsUser(TAG, 0, notif, UserHandle.of(mUserId)); 162 break; 163 164 case MSG_HIDE: 165 notifManager.cancelAsUser(TAG, 0, UserHandle.of(mUserId)); 166 break; 167 } 168 } 169 }; 170 onFinished()171 public abstract void onFinished(); 172 } 173