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