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