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