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