• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.wm;
18 
19 import static android.app.ActivityManager.START_SUCCESS;
20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
22 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
23 import static android.os.FactoryTest.FACTORY_TEST_LOW_LEVEL;
24 
25 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
26 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
27 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
28 
29 import android.annotation.Nullable;
30 import android.app.ActivityOptions;
31 import android.app.IApplicationThread;
32 import android.content.ComponentName;
33 import android.content.ContentResolver;
34 import android.content.Intent;
35 import android.content.pm.ActivityInfo;
36 import android.content.pm.ApplicationInfo;
37 import android.content.pm.PackageManager;
38 import android.content.pm.ResolveInfo;
39 import android.os.Binder;
40 import android.os.Handler;
41 import android.os.IBinder;
42 import android.os.Looper;
43 import android.os.Message;
44 import android.os.UserHandle;
45 import android.provider.Settings;
46 import android.util.Slog;
47 import android.util.SparseArray;
48 import android.util.proto.ProtoOutputStream;
49 import android.view.RemoteAnimationAdapter;
50 
51 import com.android.internal.annotations.VisibleForTesting;
52 import com.android.internal.util.ArrayUtils;
53 import com.android.server.am.ActivityManagerService;
54 import com.android.server.am.PendingIntentRecord;
55 import com.android.server.uri.NeededUriGrants;
56 import com.android.server.wm.ActivityStackSupervisor.PendingActivityLaunch;
57 import com.android.server.wm.ActivityStarter.DefaultFactory;
58 import com.android.server.wm.ActivityStarter.Factory;
59 
60 import java.io.PrintWriter;
61 import java.util.ArrayList;
62 import java.util.List;
63 
64 /**
65  * Controller for delegating activity launches.
66  *
67  * This class' main objective is to take external activity start requests and prepare them into
68  * a series of discrete activity launches that can be handled by an {@link ActivityStarter}. It is
69  * also responsible for handling logic that happens around an activity launch, but doesn't
70  * necessarily influence the activity start. Examples include power hint management, processing
71  * through the pending activity list, and recording home activity launches.
72  */
73 public class ActivityStartController {
74     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStartController" : TAG_ATM;
75 
76     private static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 1;
77 
78     private final ActivityTaskManagerService mService;
79     private final ActivityStackSupervisor mSupervisor;
80 
81     /** Last home activity record we attempted to start. */
82     private ActivityRecord mLastHomeActivityStartRecord;
83 
84     /** Temporary array to capture start activity results */
85     private ActivityRecord[] tmpOutRecord = new ActivityRecord[1];
86 
87     /** The result of the last home activity we attempted to start. */
88     private int mLastHomeActivityStartResult;
89 
90     /** A list of activities that are waiting to launch. */
91     private final ArrayList<ActivityStackSupervisor.PendingActivityLaunch>
92             mPendingActivityLaunches = new ArrayList<>();
93 
94     private final Factory mFactory;
95 
96     private final Handler mHandler;
97 
98     private final PendingRemoteAnimationRegistry mPendingRemoteAnimationRegistry;
99 
100     boolean mCheckedForSetup = false;
101 
102     private final class StartHandler extends Handler {
StartHandler(Looper looper)103         public StartHandler(Looper looper) {
104             super(looper, null, true);
105         }
106 
107         @Override
handleMessage(Message msg)108         public void handleMessage(Message msg) {
109             switch(msg.what) {
110                 case DO_PENDING_ACTIVITY_LAUNCHES_MSG:
111                     synchronized (mService.mGlobalLock) {
112                         doPendingActivityLaunches(true);
113                     }
114                     break;
115             }
116         }
117     }
118 
119     /**
120      * TODO(b/64750076): Capture information necessary for dump and
121      * {@link #postStartActivityProcessingForLastStarter} rather than keeping the entire object
122      * around
123      */
124     private ActivityStarter mLastStarter;
125 
ActivityStartController(ActivityTaskManagerService service)126     ActivityStartController(ActivityTaskManagerService service) {
127         this(service, service.mStackSupervisor,
128                 new DefaultFactory(service, service.mStackSupervisor,
129                     new ActivityStartInterceptor(service, service.mStackSupervisor)));
130     }
131 
132     @VisibleForTesting
ActivityStartController(ActivityTaskManagerService service, ActivityStackSupervisor supervisor, Factory factory)133     ActivityStartController(ActivityTaskManagerService service, ActivityStackSupervisor supervisor,
134             Factory factory) {
135         mService = service;
136         mSupervisor = supervisor;
137         mHandler = new StartHandler(mService.mH.getLooper());
138         mFactory = factory;
139         mFactory.setController(this);
140         mPendingRemoteAnimationRegistry = new PendingRemoteAnimationRegistry(service.mGlobalLock,
141                 service.mH);
142     }
143 
144     /**
145      * @return A starter to configure and execute starting an activity. It is valid until after
146      *         {@link ActivityStarter#execute} is invoked. At that point, the starter should be
147      *         considered invalid and no longer modified or used.
148      */
obtainStarter(Intent intent, String reason)149     ActivityStarter obtainStarter(Intent intent, String reason) {
150         return mFactory.obtain().setIntent(intent).setReason(reason);
151     }
152 
onExecutionComplete(ActivityStarter starter)153     void onExecutionComplete(ActivityStarter starter) {
154         if (mLastStarter == null) {
155             mLastStarter = mFactory.obtain();
156         }
157 
158         mLastStarter.set(starter);
159         mFactory.recycle(starter);
160     }
161 
162     /**
163      * TODO(b/64750076): usage of this doesn't seem right. We're making decisions based off the
164      * last starter for an arbitrary task record. Re-evaluate whether we can remove.
165      */
postStartActivityProcessingForLastStarter(ActivityRecord r, int result, ActivityStack targetStack)166     void postStartActivityProcessingForLastStarter(ActivityRecord r, int result,
167             ActivityStack targetStack) {
168         if (mLastStarter == null) {
169             return;
170         }
171 
172         mLastStarter.postStartActivityProcessing(r, result, targetStack);
173     }
174 
startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, TaskDisplayArea taskDisplayArea)175     void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason,
176             TaskDisplayArea taskDisplayArea) {
177         final ActivityOptions options = ActivityOptions.makeBasic();
178         options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
179         if (!ActivityRecord.isResolverActivity(aInfo.name)) {
180             // The resolver activity shouldn't be put in home stack because when the foreground is
181             // standard type activity, the resolver activity should be put on the top of current
182             // foreground instead of bring home stack to front.
183             options.setLaunchActivityType(ACTIVITY_TYPE_HOME);
184         }
185         final int displayId = taskDisplayArea.getDisplayId();
186         options.setLaunchDisplayId(displayId);
187         options.setLaunchTaskDisplayArea(taskDisplayArea.mRemoteToken
188                 .toWindowContainerToken());
189 
190         // The home activity will be started later, defer resuming to avoid unneccerary operations
191         // (e.g. start home recursively) when creating home stack.
192         mSupervisor.beginDeferResume();
193         final ActivityStack homeStack;
194         try {
195             // Make sure home stack exists on display area.
196             homeStack = taskDisplayArea.getOrCreateRootHomeTask(ON_TOP);
197         } finally {
198             mSupervisor.endDeferResume();
199         }
200 
201         mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)
202                 .setOutActivity(tmpOutRecord)
203                 .setCallingUid(0)
204                 .setActivityInfo(aInfo)
205                 .setActivityOptions(options.toBundle())
206                 .execute();
207         mLastHomeActivityStartRecord = tmpOutRecord[0];
208         if (homeStack.mInResumeTopActivity) {
209             // If we are in resume section already, home activity will be initialized, but not
210             // resumed (to avoid recursive resume) and will stay that way until something pokes it
211             // again. We need to schedule another resume.
212             mSupervisor.scheduleResumeTopActivities();
213         }
214     }
215 
216     /**
217      * Starts the "new version setup screen" if appropriate.
218      */
startSetupActivity()219     void startSetupActivity() {
220         // Only do this once per boot.
221         if (mCheckedForSetup) {
222             return;
223         }
224 
225         // We will show this screen if the current one is a different
226         // version than the last one shown, and we are not running in
227         // low-level factory test mode.
228         final ContentResolver resolver = mService.mContext.getContentResolver();
229         if (mService.mFactoryTest != FACTORY_TEST_LOW_LEVEL
230                 && Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
231             mCheckedForSetup = true;
232 
233             // See if we should be showing the platform update setup UI.
234             final Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
235             final List<ResolveInfo> ris =
236                     mService.mContext.getPackageManager().queryIntentActivities(intent,
237                             PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_META_DATA
238                                     | ActivityManagerService.STOCK_PM_FLAGS);
239             if (!ris.isEmpty()) {
240                 final ResolveInfo ri = ris.get(0);
241                 String vers = ri.activityInfo.metaData != null
242                         ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
243                         : null;
244                 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
245                     vers = ri.activityInfo.applicationInfo.metaData.getString(
246                             Intent.METADATA_SETUP_VERSION);
247                 }
248                 String lastVers = Settings.Secure.getString(
249                         resolver, Settings.Secure.LAST_SETUP_SHOWN);
250                 if (vers != null && !vers.equals(lastVers)) {
251                     intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
252                     intent.setComponent(new ComponentName(
253                             ri.activityInfo.packageName, ri.activityInfo.name));
254                     obtainStarter(intent, "startSetupActivity")
255                             .setCallingUid(0)
256                             .setActivityInfo(ri.activityInfo)
257                             .execute();
258                 }
259             }
260         }
261     }
262 
263     /**
264      * If {@code validateIncomingUser} is true, check {@code targetUserId} against the real calling
265      * user ID inferred from {@code realCallingUid}, then return the resolved user-id, taking into
266      * account "current user", etc.
267      *
268      * If {@code validateIncomingUser} is false, it skips the above check, but instead
269      * ensures {@code targetUserId} is a real user ID and not a special user ID such as
270      * {@link android.os.UserHandle#USER_ALL}, etc.
271      */
checkTargetUser(int targetUserId, boolean validateIncomingUser, int realCallingPid, int realCallingUid, String reason)272     int checkTargetUser(int targetUserId, boolean validateIncomingUser,
273             int realCallingPid, int realCallingUid, String reason) {
274         if (validateIncomingUser) {
275             return mService.handleIncomingUser(
276                     realCallingPid, realCallingUid, targetUserId, reason);
277         } else {
278             mService.mAmInternal.ensureNotSpecialUser(targetUserId);
279             return targetUserId;
280         }
281     }
282 
startActivityInPackage(int uid, int realCallingPid, int realCallingUid, String callingPackage, @Nullable String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, SafeActivityOptions options, int userId, Task inTask, String reason, boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart)283     final int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
284             String callingPackage, @Nullable String callingFeatureId, Intent intent,
285             String resolvedType, IBinder resultTo, String resultWho, int requestCode,
286             int startFlags, SafeActivityOptions options, int userId, Task inTask, String reason,
287             boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
288             boolean allowBackgroundActivityStart) {
289 
290         userId = checkTargetUser(userId, validateIncomingUser, realCallingPid, realCallingUid,
291                 reason);
292 
293         // TODO: Switch to user app stacks here.
294         return obtainStarter(intent, reason)
295                 .setCallingUid(uid)
296                 .setRealCallingPid(realCallingPid)
297                 .setRealCallingUid(realCallingUid)
298                 .setCallingPackage(callingPackage)
299                 .setCallingFeatureId(callingFeatureId)
300                 .setResolvedType(resolvedType)
301                 .setResultTo(resultTo)
302                 .setResultWho(resultWho)
303                 .setRequestCode(requestCode)
304                 .setStartFlags(startFlags)
305                 .setActivityOptions(options)
306                 .setUserId(userId)
307                 .setInTask(inTask)
308                 .setOriginatingPendingIntent(originatingPendingIntent)
309                 .setAllowBackgroundActivityStart(allowBackgroundActivityStart)
310                 .execute();
311     }
312 
313     /**
314      * Start intents as a package.
315      *
316      * @param uid Make a call as if this UID did.
317      * @param callingPackage Make a call as if this package did.
318      * @param callingFeatureId Make a call as if this feature in the package did.
319      * @param intents Intents to start.
320      * @param userId Start the intents on this user.
321      * @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID.
322      * @param originatingPendingIntent PendingIntentRecord that originated this activity start or
323      *        null if not originated by PendingIntent
324      */
startActivitiesInPackage(int uid, String callingPackage, @Nullable String callingFeatureId, Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId, boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart)325     final int startActivitiesInPackage(int uid, String callingPackage,
326             @Nullable String callingFeatureId, Intent[] intents, String[] resolvedTypes,
327             IBinder resultTo, SafeActivityOptions options, int userId, boolean validateIncomingUser,
328             PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
329         return startActivitiesInPackage(uid, 0 /* realCallingPid */, -1 /* realCallingUid */,
330                 callingPackage, callingFeatureId, intents, resolvedTypes, resultTo, options, userId,
331                 validateIncomingUser, originatingPendingIntent, allowBackgroundActivityStart);
332     }
333 
334     /**
335      * Start intents as a package.
336      *
337      * @param uid Make a call as if this UID did.
338      * @param realCallingPid PID of the real caller.
339      * @param realCallingUid UID of the real caller.
340      * @param callingPackage Make a call as if this package did.
341      * @param intents Intents to start.
342      * @param userId Start the intents on this user.
343      * @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID.
344      * @param originatingPendingIntent PendingIntentRecord that originated this activity start or
345      *        null if not originated by PendingIntent
346      */
startActivitiesInPackage(int uid, int realCallingPid, int realCallingUid, String callingPackage, @Nullable String callingFeatureId, Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId, boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart)347     final int startActivitiesInPackage(int uid, int realCallingPid, int realCallingUid,
348             String callingPackage, @Nullable String callingFeatureId, Intent[] intents,
349             String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
350             boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
351             boolean allowBackgroundActivityStart) {
352 
353         final String reason = "startActivityInPackage";
354 
355         userId = checkTargetUser(userId, validateIncomingUser, Binder.getCallingPid(),
356                 Binder.getCallingUid(), reason);
357 
358         // TODO: Switch to user app stacks here.
359         return startActivities(null, uid, realCallingPid, realCallingUid, callingPackage,
360                 callingFeatureId, intents, resolvedTypes, resultTo, options, userId, reason,
361                 originatingPendingIntent, allowBackgroundActivityStart);
362     }
363 
startActivities(IApplicationThread caller, int callingUid, int incomingRealCallingPid, int incomingRealCallingUid, String callingPackage, @Nullable String callingFeatureId, Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId, String reason, PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart)364     int startActivities(IApplicationThread caller, int callingUid, int incomingRealCallingPid,
365             int incomingRealCallingUid, String callingPackage, @Nullable String callingFeatureId,
366             Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options,
367             int userId, String reason, PendingIntentRecord originatingPendingIntent,
368             boolean allowBackgroundActivityStart) {
369         if (intents == null) {
370             throw new NullPointerException("intents is null");
371         }
372         if (resolvedTypes == null) {
373             throw new NullPointerException("resolvedTypes is null");
374         }
375         if (intents.length != resolvedTypes.length) {
376             throw new IllegalArgumentException("intents are length different than resolvedTypes");
377         }
378 
379         final int realCallingPid = incomingRealCallingPid != 0
380                 ? incomingRealCallingPid
381                 : Binder.getCallingPid();
382         final int realCallingUid = incomingRealCallingUid != -1
383                 ? incomingRealCallingUid
384                 : Binder.getCallingUid();
385 
386         int callingPid;
387         if (callingUid >= 0) {
388             callingPid = -1;
389         } else if (caller == null) {
390             callingPid = realCallingPid;
391             callingUid = realCallingUid;
392         } else {
393             callingPid = callingUid = -1;
394         }
395         final int filterCallingUid = ActivityStarter.computeResolveFilterUid(
396                 callingUid, realCallingUid, UserHandle.USER_NULL);
397         final SparseArray<String> startingUidPkgs = new SparseArray<>();
398         final long origId = Binder.clearCallingIdentity();
399         try {
400             intents = ArrayUtils.filterNotNull(intents, Intent[]::new);
401             final ActivityStarter[] starters = new ActivityStarter[intents.length];
402             // Do not hold WM global lock on this loop because when resolving intent, it may
403             // potentially acquire activity manager lock that leads to deadlock.
404             for (int i = 0; i < intents.length; i++) {
405                 Intent intent = intents[i];
406                 NeededUriGrants intentGrants = null;
407 
408                 // Refuse possible leaked file descriptors.
409                 if (intent.hasFileDescriptors()) {
410                     throw new IllegalArgumentException("File descriptors passed in Intent");
411                 }
412 
413                 // Get the flag earlier because the intent may be modified in resolveActivity below.
414                 final boolean componentSpecified = intent.getComponent() != null;
415                 // Don't modify the client's object!
416                 intent = new Intent(intent);
417 
418                 // Collect information about the target of the Intent.
419                 ActivityInfo aInfo = mSupervisor.resolveActivity(intent, resolvedTypes[i],
420                         0 /* startFlags */, null /* profilerInfo */, userId, filterCallingUid);
421                 aInfo = mService.mAmInternal.getActivityInfoForUser(aInfo, userId);
422 
423                 // Carefully collect grants without holding lock
424                 if (aInfo != null) {
425                     intentGrants = mSupervisor.mService.mUgmInternal
426                             .checkGrantUriPermissionFromIntent(intent, filterCallingUid,
427                                     aInfo.applicationInfo.packageName,
428                                     UserHandle.getUserId(aInfo.applicationInfo.uid));
429                 }
430 
431                 if (aInfo != null) {
432                     if ((aInfo.applicationInfo.privateFlags
433                             & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
434                         throw new IllegalArgumentException(
435                                 "FLAG_CANT_SAVE_STATE not supported here");
436                     }
437                     startingUidPkgs.put(aInfo.applicationInfo.uid,
438                             aInfo.applicationInfo.packageName);
439                 }
440 
441                 final boolean top = i == intents.length - 1;
442                 final SafeActivityOptions checkedOptions = top
443                         ? options
444                         : null;
445                 starters[i] = obtainStarter(intent, reason)
446                         .setIntentGrants(intentGrants)
447                         .setCaller(caller)
448                         .setResolvedType(resolvedTypes[i])
449                         .setActivityInfo(aInfo)
450                         .setRequestCode(-1)
451                         .setCallingPid(callingPid)
452                         .setCallingUid(callingUid)
453                         .setCallingPackage(callingPackage)
454                         .setCallingFeatureId(callingFeatureId)
455                         .setRealCallingPid(realCallingPid)
456                         .setRealCallingUid(realCallingUid)
457                         .setActivityOptions(checkedOptions)
458                         .setComponentSpecified(componentSpecified)
459 
460                         // Top activity decides on animation being run, so we allow only for the
461                         // top one as otherwise an activity below might consume it.
462                         .setAllowPendingRemoteAnimationRegistryLookup(top /* allowLookup*/)
463                         .setOriginatingPendingIntent(originatingPendingIntent)
464                         .setAllowBackgroundActivityStart(allowBackgroundActivityStart);
465             }
466             // Log if the activities to be started have different uids.
467             if (startingUidPkgs.size() > 1) {
468                 final StringBuilder sb = new StringBuilder("startActivities: different apps [");
469                 final int size = startingUidPkgs.size();
470                 for (int i = 0; i < size; i++) {
471                     sb.append(startingUidPkgs.valueAt(i)).append(i == size - 1 ? "]" : ", ");
472                 }
473                 sb.append(" from ").append(callingPackage);
474                 Slog.wtf(TAG, sb.toString());
475             }
476 
477             final IBinder sourceResultTo = resultTo;
478             final ActivityRecord[] outActivity = new ActivityRecord[1];
479             // Lock the loop to ensure the activities launched in a sequence.
480             synchronized (mService.mGlobalLock) {
481                 mService.deferWindowLayout();
482                 try {
483                     for (int i = 0; i < starters.length; i++) {
484                         final int startResult = starters[i].setResultTo(resultTo)
485                                 .setOutActivity(outActivity).execute();
486                         if (startResult < START_SUCCESS) {
487                             // Abort by error result and recycle unused starters.
488                             for (int j = i + 1; j < starters.length; j++) {
489                                 mFactory.recycle(starters[j]);
490                             }
491                             return startResult;
492                         }
493                         final ActivityRecord started = outActivity[0];
494                         if (started != null && started.getUid() == filterCallingUid) {
495                             // Only the started activity which has the same uid as the source caller
496                             // can be the caller of next activity.
497                             resultTo = started.appToken;
498                         } else {
499                             resultTo = sourceResultTo;
500                             // Different apps not adjacent to the caller are forced to be new task.
501                             if (i < starters.length - 1) {
502                                 starters[i + 1].getIntent().addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
503                             }
504                         }
505                     }
506                 } finally {
507                     mService.continueWindowLayout();
508                 }
509             }
510         } finally {
511             Binder.restoreCallingIdentity(origId);
512         }
513 
514         return START_SUCCESS;
515     }
516 
schedulePendingActivityLaunches(long delayMs)517     void schedulePendingActivityLaunches(long delayMs) {
518         mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
519         Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
520         mHandler.sendMessageDelayed(msg, delayMs);
521     }
522 
doPendingActivityLaunches(boolean doResume)523     void doPendingActivityLaunches(boolean doResume) {
524         while (!mPendingActivityLaunches.isEmpty()) {
525             final PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
526             final boolean resume = doResume && mPendingActivityLaunches.isEmpty();
527             final ActivityStarter starter = obtainStarter(null /* intent */,
528                     "pendingActivityLaunch");
529             try {
530                 starter.startResolvedActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags,
531                         resume, pal.r.pendingOptions, null, pal.intentGrants);
532             } catch (Exception e) {
533                 Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
534                 pal.sendErrorResult(e.getMessage());
535             }
536         }
537     }
538 
addPendingActivityLaunch(PendingActivityLaunch launch)539     void addPendingActivityLaunch(PendingActivityLaunch launch) {
540         mPendingActivityLaunches.add(launch);
541     }
542 
clearPendingActivityLaunches(String packageName)543     boolean clearPendingActivityLaunches(String packageName) {
544         final int pendingLaunches = mPendingActivityLaunches.size();
545 
546         for (int palNdx = pendingLaunches - 1; palNdx >= 0; --palNdx) {
547             final PendingActivityLaunch pal = mPendingActivityLaunches.get(palNdx);
548             final ActivityRecord r = pal.r;
549             if (r != null && r.packageName.equals(packageName)) {
550                 mPendingActivityLaunches.remove(palNdx);
551             }
552         }
553         return mPendingActivityLaunches.size() < pendingLaunches;
554     }
555 
registerRemoteAnimationForNextActivityStart(String packageName, RemoteAnimationAdapter adapter)556     void registerRemoteAnimationForNextActivityStart(String packageName,
557             RemoteAnimationAdapter adapter) {
558         mPendingRemoteAnimationRegistry.addPendingAnimation(packageName, adapter);
559     }
560 
getPendingRemoteAnimationRegistry()561     PendingRemoteAnimationRegistry getPendingRemoteAnimationRegistry() {
562         return mPendingRemoteAnimationRegistry;
563     }
564 
dumpLastHomeActivityStartResult(PrintWriter pw, String prefix)565     void dumpLastHomeActivityStartResult(PrintWriter pw, String prefix) {
566         pw.print(prefix);
567         pw.print("mLastHomeActivityStartResult=");
568         pw.println(mLastHomeActivityStartResult);
569     }
570 
dump(PrintWriter pw, String prefix, String dumpPackage)571     void dump(PrintWriter pw, String prefix, String dumpPackage) {
572         boolean dumped = false;
573 
574         final boolean dumpPackagePresent = dumpPackage != null;
575 
576         if (mLastHomeActivityStartRecord != null && (!dumpPackagePresent
577                 || dumpPackage.equals(mLastHomeActivityStartRecord.packageName))) {
578             if (!dumped) {
579                 dumped = true;
580                 dumpLastHomeActivityStartResult(pw, prefix);
581             }
582             pw.print(prefix);
583             pw.println("mLastHomeActivityStartRecord:");
584             mLastHomeActivityStartRecord.dump(pw, prefix + "  ", true /* dumpAll */);
585         }
586 
587         if (mLastStarter != null) {
588             final boolean dump = !dumpPackagePresent
589                     || mLastStarter.relatedToPackage(dumpPackage)
590                     || (mLastHomeActivityStartRecord != null
591                             && dumpPackage.equals(mLastHomeActivityStartRecord.packageName));
592 
593             if (dump) {
594                 if (!dumped) {
595                     dumped = true;
596                     dumpLastHomeActivityStartResult(pw, prefix);
597                 }
598                 pw.print(prefix);
599                 mLastStarter.dump(pw, prefix + "  ");
600 
601                 if (dumpPackagePresent) {
602                     return;
603                 }
604             }
605         }
606 
607         if (!dumped) {
608             pw.print(prefix);
609             pw.println("(nothing)");
610         }
611     }
612 
dumpDebug(ProtoOutputStream proto, long fieldId)613     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
614         for (PendingActivityLaunch activity: mPendingActivityLaunches) {
615             activity.r.writeIdentifierToProto(proto, fieldId);
616         }
617     }
618 }
619