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