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 import static android.os.PowerWhitelistManager.REASON_PRE_BOOT_COMPLETED; 21 import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED; 22 23 import android.app.ActivityManagerInternal; 24 import android.app.AppOpsManager; 25 import android.app.BroadcastOptions; 26 import android.app.Notification; 27 import android.app.NotificationManager; 28 import android.app.PendingIntent; 29 import android.content.ComponentName; 30 import android.content.Context; 31 import android.content.IIntentReceiver; 32 import android.content.Intent; 33 import android.content.pm.ResolveInfo; 34 import android.os.Binder; 35 import android.os.Bundle; 36 import android.os.Handler; 37 import android.os.Message; 38 import android.os.Process; 39 import android.os.UserHandle; 40 import android.util.Slog; 41 42 import com.android.internal.R; 43 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; 44 import com.android.internal.notification.SystemNotificationChannels; 45 import com.android.internal.util.ProgressReporter; 46 import com.android.server.LocalServices; 47 import com.android.server.UiThread; 48 49 import java.util.List; 50 51 /** 52 * Simple broadcaster that sends {@link Intent#ACTION_PRE_BOOT_COMPLETED} to all 53 * system apps that register for it. Override {@link #onFinished()} to handle 54 * when all broadcasts are finished. 55 */ 56 public abstract class PreBootBroadcaster extends IIntentReceiver.Stub { 57 private static final String TAG = "PreBootBroadcaster"; 58 59 private final ActivityManagerService mService; 60 private final int mUserId; 61 private final ProgressReporter mProgress; 62 private final boolean mQuiet; 63 64 private final Intent mIntent; 65 private final List<ResolveInfo> mTargets; 66 67 private int mIndex = 0; 68 PreBootBroadcaster(ActivityManagerService service, int userId, ProgressReporter progress, boolean quiet)69 public PreBootBroadcaster(ActivityManagerService service, int userId, 70 ProgressReporter progress, boolean quiet) { 71 mService = service; 72 mUserId = userId; 73 mProgress = progress; 74 mQuiet = quiet; 75 76 mIntent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED); 77 mIntent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE | Intent.FLAG_DEBUG_TRIAGED_MISSING); 78 79 mTargets = mService.mContext.getPackageManager().queryBroadcastReceiversAsUser(mIntent, 80 MATCH_SYSTEM_ONLY, UserHandle.of(userId)); 81 } 82 sendNext()83 public void sendNext() { 84 if (mIndex >= mTargets.size()) { 85 mHandler.obtainMessage(MSG_HIDE).sendToTarget(); 86 onFinished(); 87 return; 88 } 89 90 if (!mService.isUserRunning(mUserId, 0)) { 91 Slog.i(TAG, "User " + mUserId + " is no longer running; skipping remaining receivers"); 92 mHandler.obtainMessage(MSG_HIDE).sendToTarget(); 93 onFinished(); 94 return; 95 } 96 97 if (!mQuiet) { 98 mHandler.obtainMessage(MSG_SHOW, mTargets.size(), mIndex).sendToTarget(); 99 } 100 101 final ResolveInfo ri = mTargets.get(mIndex++); 102 final ComponentName componentName = ri.activityInfo.getComponentName(); 103 104 if (mProgress != null) { 105 final CharSequence label = ri.activityInfo 106 .loadLabel(mService.mContext.getPackageManager()); 107 mProgress.setProgress(mIndex, mTargets.size(), 108 mService.mContext.getString(R.string.android_preparing_apk, label)); 109 } 110 111 Slog.i(TAG, "Pre-boot of " + componentName.toShortString() + " for user " + mUserId); 112 EventLogTags.writeAmPreBoot(mUserId, componentName.getPackageName()); 113 114 mIntent.setComponent(componentName); 115 long duration = 10_000; 116 final ActivityManagerInternal amInternal = 117 LocalServices.getService(ActivityManagerInternal.class); 118 if (amInternal != null) { 119 duration = amInternal.getBootTimeTempAllowListDuration(); 120 } 121 final BroadcastOptions bOptions = BroadcastOptions.makeBasic(); 122 bOptions.setTemporaryAppAllowlist(duration, 123 TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, 124 REASON_PRE_BOOT_COMPLETED, ""); 125 synchronized (mService) { 126 mService.broadcastIntentLocked(null, null, null, mIntent, null, this, 0, 127 null, null, null, null, null, AppOpsManager.OP_NONE, bOptions.toBundle(), true, 128 false, ActivityManagerService.MY_PID, 129 Process.SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(), mUserId); 130 } 131 } 132 133 @Override performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser)134 public void performReceive(Intent intent, int resultCode, String data, Bundle extras, 135 boolean ordered, boolean sticky, int sendingUser) { 136 sendNext(); 137 } 138 139 private static final int MSG_SHOW = 1; 140 private static final int MSG_HIDE = 2; 141 142 private Handler mHandler = new Handler(UiThread.get().getLooper(), null, true) { 143 @Override 144 public void handleMessage(Message msg) { 145 final Context context = mService.mContext; 146 final NotificationManager notifManager = context 147 .getSystemService(NotificationManager.class); 148 final int max = msg.arg1; 149 final int index = msg.arg2; 150 151 switch (msg.what) { 152 case MSG_SHOW: 153 final CharSequence title = context 154 .getText(R.string.android_upgrading_notification_title); 155 156 final Intent intent = new Intent(); 157 intent.setClassName("com.android.settings", 158 "com.android.settings.HelpTrampoline"); 159 intent.putExtra(Intent.EXTRA_TEXT, "help_url_upgrading"); 160 161 final PendingIntent contentIntent; 162 if (context.getPackageManager().resolveActivity(intent, 0) != null) { 163 contentIntent = PendingIntent.getActivity(context, 0, intent, 164 PendingIntent.FLAG_IMMUTABLE); 165 } else { 166 contentIntent = null; 167 } 168 169 final Notification notif = 170 new Notification.Builder(mService.mContext, 171 SystemNotificationChannels.UPDATES) 172 .setSmallIcon(R.drawable.stat_sys_adb) 173 .setWhen(0) 174 .setOngoing(true) 175 .setTicker(title) 176 .setColor(context.getColor( 177 com.android.internal.R.color.system_notification_accent_color)) 178 .setContentTitle(title) 179 .setContentIntent(contentIntent) 180 .setVisibility(Notification.VISIBILITY_PUBLIC) 181 .setProgress(max, index, false) 182 .build(); 183 notifManager.notifyAsUser(TAG, SystemMessage.NOTE_SYSTEM_UPGRADING, notif, 184 UserHandle.of(mUserId)); 185 break; 186 187 case MSG_HIDE: 188 notifManager.cancelAsUser(TAG, SystemMessage.NOTE_SYSTEM_UPGRADING, 189 UserHandle.of(mUserId)); 190 break; 191 } 192 } 193 }; 194 onFinished()195 public abstract void onFinished(); 196 } 197