1 /* 2 * Copyright (C) 2019 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 android.app; 18 19 import android.annotation.FlaggedApi; 20 import android.annotation.IntDef; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.SuppressLint; 24 import android.content.Intent; 25 import android.content.pm.ApplicationInfo; 26 import android.icu.text.SimpleDateFormat; 27 import android.os.Parcel; 28 import android.os.Parcelable; 29 import android.os.UserHandle; 30 import android.text.TextUtils; 31 import android.util.ArrayMap; 32 import android.util.Xml; 33 import android.util.proto.ProtoInputStream; 34 import android.util.proto.ProtoOutputStream; 35 import android.util.proto.WireTypeMismatchException; 36 37 import com.android.internal.util.XmlUtils; 38 import com.android.modules.utils.TypedXmlPullParser; 39 import com.android.modules.utils.TypedXmlSerializer; 40 41 import org.xmlpull.v1.XmlPullParserException; 42 43 import java.io.ByteArrayInputStream; 44 import java.io.ByteArrayOutputStream; 45 import java.io.IOException; 46 import java.io.ObjectInputStream; 47 import java.io.ObjectOutputStream; 48 import java.io.PrintWriter; 49 import java.lang.annotation.Retention; 50 import java.lang.annotation.RetentionPolicy; 51 import java.util.Map; 52 import java.util.Objects; 53 54 /** 55 * Describes information related to an application process's startup. 56 * 57 * <p> 58 * Many aspects concerning why and how an applications process was started are valuable for apps 59 * both for logging and for potential behavior changes. Reason for process start, start type, 60 * start times, throttling, and other useful diagnostic data can be obtained from 61 * {@link ApplicationStartInfo} records. 62 * </p> 63 * 64 * <p> 65 * ApplicationStartInfo objects can be retrieved via: 66 * - {@link ActivityManager#getHistoricalProcessStartReasons}, which can be called during or after 67 * a application's startup. Using this method, an app can retrieve information about an 68 * in-progress app start. 69 * - {@link ActivityManager#addApplicationStartInfoCompletionListener}, which returns an 70 * ApplicationStartInfo object via a callback when the startup is complete, or immediately 71 * if requested after the startup is complete. 72 * </p> 73 */ 74 @FlaggedApi(Flags.FLAG_APP_START_INFO) 75 public final class ApplicationStartInfo implements Parcelable { 76 77 /** 78 * State indicating process startup has started. Some information is available in 79 * {@link ApplicationStartInfo} and more will be added. 80 */ 81 public static final int STARTUP_STATE_STARTED = 0; 82 83 /** 84 * State indicating process startup has failed. Startup information in 85 * {@link ApplicationStartInfo} is incomplete, but no more will be added. 86 */ 87 public static final int STARTUP_STATE_ERROR = 1; 88 89 /** 90 * State indicating process startup has made it to first frame draw. Startup 91 * information in {@link ApplicationStartInfo} is complete with potential exception 92 * of fully drawn timestamp which is not guaranteed to be set. 93 */ 94 public static final int STARTUP_STATE_FIRST_FRAME_DRAWN = 2; 95 96 /** Process started due to alarm. */ 97 public static final int START_REASON_ALARM = 0; 98 99 /** Process started to run backup. */ 100 public static final int START_REASON_BACKUP = 1; 101 102 /** Process started due to boot complete. */ 103 public static final int START_REASON_BOOT_COMPLETE = 2; 104 105 /** Process started due to broadcast received. */ 106 public static final int START_REASON_BROADCAST = 3; 107 108 /** Process started due to access of ContentProvider */ 109 public static final int START_REASON_CONTENT_PROVIDER = 4; 110 111 /** * Process started to run scheduled job. */ 112 public static final int START_REASON_JOB = 5; 113 114 /** Process started due to click app icon or widget from launcher. */ 115 public static final int START_REASON_LAUNCHER = 6; 116 117 /** Process started from launcher recents. */ 118 public static final int START_REASON_LAUNCHER_RECENTS = 7; 119 120 /** Process started not for any of the listed reasons. */ 121 public static final int START_REASON_OTHER = 8; 122 123 /** Process started due to push message. */ 124 public static final int START_REASON_PUSH = 9; 125 126 /** Process service started. */ 127 public static final int START_REASON_SERVICE = 10; 128 129 /** Process started due to Activity started for any reason not explicitly listed. */ 130 public static final int START_REASON_START_ACTIVITY = 11; 131 132 /** Start type not yet set. */ 133 public static final int START_TYPE_UNSET = 0; 134 135 /** Process started from scratch. */ 136 public static final int START_TYPE_COLD = 1; 137 138 /** Process retained minimally SavedInstanceState. */ 139 public static final int START_TYPE_WARM = 2; 140 141 /** Process brought back to foreground. */ 142 public static final int START_TYPE_HOT = 3; 143 144 /** 145 * Default. The system always creates a new instance of the activity in the target task and 146 * routes the intent to it. 147 */ 148 public static final int LAUNCH_MODE_STANDARD = 0; 149 150 /** 151 * If an instance of the activity already exists at the top of the target task, the system 152 * routes the intent to that instance through a call to its onNewIntent() method, rather than 153 * creating a new instance of the activity. 154 */ 155 public static final int LAUNCH_MODE_SINGLE_TOP = 1; 156 157 /** 158 * The system creates the activity at the root of a new task or locates the activity on an 159 * existing task with the same affinity. If an instance of the activity already exists and is at 160 * the root of the task, the system routes the intent to existing instance through a call to its 161 * onNewIntent() method, rather than creating a new one. 162 */ 163 public static final int LAUNCH_MODE_SINGLE_INSTANCE = 2; 164 165 /** 166 * Same as "singleTask", except that the system doesn't launch any other activities into the 167 * task holding the instance. The activity is always the single and only member of its task. 168 */ 169 public static final int LAUNCH_MODE_SINGLE_TASK = 3; 170 171 /** 172 * The activity can only be running as the root activity of the task, the first activity that 173 * created the task, and therefore there will only be one instance of this activity in a task; 174 * but activity can be instantiated multiple times in different tasks. 175 */ 176 public static final int LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK = 4; 177 178 /** The end of the range, beginning with 0, reserved for system timestamps.*/ 179 public static final int START_TIMESTAMP_RESERVED_RANGE_SYSTEM = 20; 180 181 /** The beginning of the range reserved for developer supplied timestamps.*/ 182 public static final int START_TIMESTAMP_RESERVED_RANGE_DEVELOPER_START = 183 START_TIMESTAMP_RESERVED_RANGE_SYSTEM + 1; 184 185 /** The end of the range reserved for developer supplied timestamps.*/ 186 public static final int START_TIMESTAMP_RESERVED_RANGE_DEVELOPER = 30; 187 188 /** Clock monotonic timestamp of launch started. */ 189 public static final int START_TIMESTAMP_LAUNCH = 0; 190 191 /** Clock monotonic timestamp of process fork. */ 192 public static final int START_TIMESTAMP_FORK = 1; 193 194 /** Clock monotonic timestamp of Application onCreate called. */ 195 public static final int START_TIMESTAMP_APPLICATION_ONCREATE = 2; 196 197 /** Clock monotonic timestamp of bindApplication called. */ 198 public static final int START_TIMESTAMP_BIND_APPLICATION = 3; 199 200 /** Clock monotonic timestamp of first frame drawn. */ 201 public static final int START_TIMESTAMP_FIRST_FRAME = 4; 202 203 /** Clock monotonic timestamp of reportFullyDrawn called by application. */ 204 public static final int START_TIMESTAMP_FULLY_DRAWN = 5; 205 206 /** Clock monotonic timestamp of initial renderthread frame. */ 207 public static final int START_TIMESTAMP_INITIAL_RENDERTHREAD_FRAME = 6; 208 209 /** Clock monotonic timestamp of surfaceflinger composition complete. */ 210 public static final int START_TIMESTAMP_SURFACEFLINGER_COMPOSITION_COMPLETE = 7; 211 212 /** 213 * @see #getStartupState 214 */ 215 private @StartupState int mStartupState; 216 217 /** 218 * @see #getPid 219 */ 220 private int mPid; 221 222 /** 223 * @see #getRealUid 224 */ 225 private int mRealUid; 226 227 /** 228 * @see #getPackageUid 229 */ 230 private int mPackageUid; 231 232 /** 233 * @see #getDefiningUid 234 */ 235 private int mDefiningUid; 236 237 /** 238 * @see #getPackageName 239 */ 240 private String mPackageName; 241 242 /** 243 * @see #getProcessName 244 */ 245 private String mProcessName; 246 247 /** 248 * @see #getReason 249 */ 250 private @StartReason int mReason; 251 252 /** 253 * @see #getStartupTimestamps 254 */ 255 private ArrayMap<Integer, Long> mStartupTimestampsNs; 256 257 /** 258 * @see #getStartType 259 */ 260 private @StartType int mStartType; 261 262 /** 263 * @see #getIntent 264 */ 265 private Intent mStartIntent; 266 267 /** 268 * @see #getLaunchMode 269 */ 270 private @LaunchMode int mLaunchMode; 271 272 /** 273 * @see #wasForceStopped() 274 */ 275 private boolean mWasForceStopped; 276 277 /** 278 * @hide * 279 */ 280 @IntDef( 281 prefix = {"STARTUP_STATE_"}, 282 value = { 283 STARTUP_STATE_STARTED, 284 STARTUP_STATE_ERROR, 285 STARTUP_STATE_FIRST_FRAME_DRAWN, 286 }) 287 @Retention(RetentionPolicy.SOURCE) 288 public @interface StartupState {} 289 290 /** 291 * @hide * 292 */ 293 @IntDef( 294 prefix = {"START_REASON_"}, 295 value = { 296 START_REASON_ALARM, 297 START_REASON_BACKUP, 298 START_REASON_BOOT_COMPLETE, 299 START_REASON_BROADCAST, 300 START_REASON_CONTENT_PROVIDER, 301 START_REASON_JOB, 302 START_REASON_LAUNCHER, 303 START_REASON_LAUNCHER_RECENTS, 304 START_REASON_OTHER, 305 START_REASON_PUSH, 306 START_REASON_SERVICE, 307 START_REASON_START_ACTIVITY, 308 }) 309 @Retention(RetentionPolicy.SOURCE) 310 public @interface StartReason {} 311 312 /** 313 * @hide * 314 */ 315 @IntDef( 316 prefix = {"START_TYPE_"}, 317 value = { 318 START_TYPE_UNSET, 319 START_TYPE_COLD, 320 START_TYPE_WARM, 321 START_TYPE_HOT, 322 }) 323 @Retention(RetentionPolicy.SOURCE) 324 public @interface StartType {} 325 326 /** 327 * @hide * 328 */ 329 @IntDef( 330 prefix = {"LAUNCH_MODE_"}, 331 value = { 332 LAUNCH_MODE_STANDARD, 333 LAUNCH_MODE_SINGLE_TOP, 334 LAUNCH_MODE_SINGLE_INSTANCE, 335 LAUNCH_MODE_SINGLE_TASK, 336 LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK, 337 }) 338 @Retention(RetentionPolicy.SOURCE) 339 public @interface LaunchMode {} 340 341 /** 342 * @see #getStartupState 343 * @hide 344 */ setStartupState(final @StartupState int startupState)345 public void setStartupState(final @StartupState int startupState) { 346 mStartupState = startupState; 347 } 348 349 /** 350 * @see #getPid 351 * @hide 352 */ setPid(final int pid)353 public void setPid(final int pid) { 354 mPid = pid; 355 } 356 357 /** 358 * @see #getRealUid 359 * @hide 360 */ setRealUid(final int uid)361 public void setRealUid(final int uid) { 362 mRealUid = uid; 363 } 364 365 /** 366 * @see #getPackageUid 367 * @hide 368 */ setPackageUid(final int uid)369 public void setPackageUid(final int uid) { 370 mPackageUid = uid; 371 } 372 373 /** 374 * @see #getDefiningUid 375 * @hide 376 */ setDefiningUid(final int uid)377 public void setDefiningUid(final int uid) { 378 mDefiningUid = uid; 379 } 380 381 /** 382 * @see #getPackageName 383 * @hide 384 */ setPackageName(final String packageName)385 public void setPackageName(final String packageName) { 386 mPackageName = intern(packageName); 387 } 388 389 /** 390 * @see #getProcessName 391 * @hide 392 */ setProcessName(final String processName)393 public void setProcessName(final String processName) { 394 mProcessName = intern(processName); 395 } 396 397 /** 398 * @see #getReason 399 * @hide 400 */ setReason(@tartReason int reason)401 public void setReason(@StartReason int reason) { 402 mReason = reason; 403 } 404 405 /** 406 * @see #getStartupTimestamps 407 * @hide 408 */ addStartupTimestamp(int key, long timestampNs)409 public void addStartupTimestamp(int key, long timestampNs) { 410 if (key < 0 || key > START_TIMESTAMP_RESERVED_RANGE_DEVELOPER) { 411 return; 412 } 413 if (mStartupTimestampsNs == null) { 414 mStartupTimestampsNs = new ArrayMap<Integer, Long>(); 415 } 416 mStartupTimestampsNs.put(key, timestampNs); 417 } 418 419 /** 420 * @see #getStartType 421 * @hide 422 */ setStartType(@tartType int startType)423 public void setStartType(@StartType int startType) { 424 mStartType = startType; 425 } 426 427 /** 428 * @see #getStartIntent 429 * 430 * <p class="note"> Note: This method will clone the provided intent and ensure that the cloned 431 * intent doesn't contain any large objects like bitmaps in its extras by stripping it in the 432 * least aggressive acceptable way for the individual intent.</p> 433 * 434 * @hide 435 */ setIntent(Intent startIntent)436 public void setIntent(Intent startIntent) { 437 if (startIntent != null) { 438 if (startIntent.canStripForHistory()) { 439 // If maybeStripForHistory will return a lightened version, do that. 440 mStartIntent = startIntent.maybeStripForHistory(); 441 } else if (startIntent.getExtras() != null) { 442 // If maybeStripForHistory would not return a lightened version and extras is 443 // non-null then extras contains un-parcelled data. Use cloneFilter to strip data 444 // more aggressively. 445 mStartIntent = startIntent.cloneFilter(); 446 } else { 447 // Finally, if maybeStripForHistory would not return a lightened version and extras 448 // is null then do a regular clone so we don't leak the intent. 449 mStartIntent = new Intent(startIntent); 450 } 451 452 // If the newly cloned intent has an original intent, clear that as we don't need it and 453 // can't guarantee it doesn't need to be stripped as well. 454 if (mStartIntent.getOriginalIntent() != null) { 455 mStartIntent.setOriginalIntent(null); 456 } 457 } 458 } 459 460 /** 461 * @see #getLaunchMode 462 * @hide 463 */ setLaunchMode(@aunchMode int launchMode)464 public void setLaunchMode(@LaunchMode int launchMode) { 465 mLaunchMode = launchMode; 466 } 467 468 /** 469 * @see #wasForceStopped() 470 * @param wasForceStopped whether the app had been force-stopped in the past 471 * @hide 472 */ setForceStopped(boolean wasForceStopped)473 public void setForceStopped(boolean wasForceStopped) { 474 mWasForceStopped = wasForceStopped; 475 } 476 477 /** 478 * Current state of startup. 479 * 480 * Can be used to determine whether the object will have additional fields added as it may be 481 * queried before all data is collected. 482 * 483 * <p class="note"> Note: field will always be set and available.</p> 484 */ getStartupState()485 public @StartupState int getStartupState() { 486 return mStartupState; 487 } 488 489 /** 490 * The process id. 491 * 492 * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p> 493 */ getPid()494 public int getPid() { 495 return mPid; 496 } 497 498 /** 499 * The kernel user identifier of the process, most of the time the system uses this to do access 500 * control checks. It's typically the uid of the package where the component is running from, 501 * except the case of isolated process, where this field identifies the kernel user identifier 502 * that this process is actually running with, while the {@link #getPackageUid} identifies the 503 * kernel user identifier that is assigned at the package installation time. 504 * 505 * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p> 506 */ getRealUid()507 public int getRealUid() { 508 return mRealUid; 509 } 510 511 /** 512 * Similar to {@link #getRealUid}, it's the kernel user identifier that is assigned at the 513 * package installation time. 514 * 515 * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p> 516 */ getPackageUid()517 public int getPackageUid() { 518 return mPackageUid; 519 } 520 521 /** 522 * Return the defining kernel user identifier, maybe different from {@link #getRealUid} and 523 * {@link #getPackageUid}, if an external service has the {@link 524 * android.R.styleable#AndroidManifestService_useAppZygote android:useAppZygote} set to <code> 525 * true</code> and was bound with the flag {@link android.content.Context#BIND_EXTERNAL_SERVICE} 526 * - in this case, this field here will be the kernel user identifier of the external service 527 * provider. 528 * 529 * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p> 530 */ getDefiningUid()531 public int getDefiningUid() { 532 return mDefiningUid; 533 } 534 535 /** 536 * Name of first package running in this process; 537 * 538 * @hide 539 */ getPackageName()540 public String getPackageName() { 541 return mPackageName; 542 } 543 544 /** 545 * The actual process name it was running with. 546 * 547 * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p> 548 */ getProcessName()549 public @NonNull String getProcessName() { 550 return mProcessName; 551 } 552 553 /** 554 * The reason code of what triggered the process's start. 555 * 556 * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p> 557 */ getReason()558 public @StartReason int getReason() { 559 return mReason; 560 } 561 562 /** 563 * Various clock monotonic timestamps in nanoseconds throughout the startup process. 564 * 565 * <p class="note"> Note: different timestamps will be available for different values of 566 * {@link #getStartupState}: 567 * 568 * (Subsequent rows contain all timestamps of proceding states.) 569 * 570 * For {@link #STARTUP_STATE_STARTED}, timestamp {@link #START_TIMESTAMP_LAUNCH} will be 571 * available. 572 * For {@link #STARTUP_STATE_ERROR}, no additional timestamps are guaranteed available. 573 * For {@link #STARTUP_STATE_FIRST_FRAME_DRAWN}, timestamps 574 * {@link #START_TIMESTAMP_APPLICATION_ONCREATE}, {@link #START_TIMESTAMP_BIND_APPLICATION}, 575 * and {@link #START_TIMESTAMP_FIRST_FRAME} will additionally be available. 576 * 577 * Timestamp {@link #START_TIMESTAMP_FULLY_DRAWN} is never guaranteed to be available as it is 578 * dependant on devloper calling {@link Activity#reportFullyDrawn}. 579 * </p> 580 */ getStartupTimestamps()581 public @NonNull Map<Integer, Long> getStartupTimestamps() { 582 if (mStartupTimestampsNs == null) { 583 mStartupTimestampsNs = new ArrayMap<Integer, Long>(); 584 } 585 return mStartupTimestampsNs; 586 } 587 588 /** 589 * The state of the app at startup. 590 * 591 * <p class="note"> Note: field will be set for {@link #getStartupState} value 592 * {@link #STARTUP_STATE_FIRST_FRAME_DRAWN}. Not guaranteed for other states.</p> 593 */ getStartType()594 public @StartType int getStartType() { 595 return mStartType; 596 } 597 598 /** 599 * The intent used to launch the application. 600 * 601 * <p class="note"> Note: Intent is stripped and does not include extras.</p> 602 * 603 * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p> 604 */ 605 @SuppressLint("IntentBuilderName") 606 @Nullable getIntent()607 public Intent getIntent() { 608 return mStartIntent; 609 } 610 611 /** 612 * An instruction on how the activity should be launched. There are five modes that work in 613 * conjunction with activity flags in Intent objects to determine what should happen when the 614 * activity is called upon to handle an intent. 615 * 616 * Modes: 617 * {@link #LAUNCH_MODE_STANDARD} 618 * {@link #LAUNCH_MODE_SINGLE_TOP} 619 * {@link #LAUNCH_MODE_SINGLE_INSTANCE} 620 * {@link #LAUNCH_MODE_SINGLE_TASK} 621 * {@link #LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK} 622 * 623 * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p> 624 */ getLaunchMode()625 public @LaunchMode int getLaunchMode() { 626 return mLaunchMode; 627 } 628 629 /** 630 * Informs whether this is the first process launch for an app since it was 631 * {@link ApplicationInfo#FLAG_STOPPED force-stopped} for some reason. 632 * This allows the app to know if it should re-register for any alarms, jobs and other callbacks 633 * that were cleared when the app was force-stopped. 634 * 635 * @return {@code true} if this is the first process launch of the app after having been 636 * stopped, {@code false} otherwise. 637 */ 638 @FlaggedApi(android.content.pm.Flags.FLAG_STAY_STOPPED) wasForceStopped()639 public boolean wasForceStopped() { 640 return mWasForceStopped; 641 } 642 643 @Override describeContents()644 public int describeContents() { 645 return 0; 646 } 647 648 @Override writeToParcel(@onNull Parcel dest, int flags)649 public void writeToParcel(@NonNull Parcel dest, int flags) { 650 dest.writeInt(mStartupState); 651 dest.writeInt(mPid); 652 dest.writeInt(mRealUid); 653 dest.writeInt(mPackageUid); 654 dest.writeInt(mDefiningUid); 655 dest.writeString(mPackageName); 656 dest.writeString(mProcessName); 657 dest.writeInt(mReason); 658 dest.writeInt(mStartupTimestampsNs == null ? 0 : mStartupTimestampsNs.size()); 659 if (mStartupTimestampsNs != null) { 660 for (int i = 0; i < mStartupTimestampsNs.size(); i++) { 661 dest.writeInt(mStartupTimestampsNs.keyAt(i)); 662 dest.writeLong(mStartupTimestampsNs.valueAt(i)); 663 } 664 } 665 dest.writeInt(mStartType); 666 dest.writeParcelable(mStartIntent, flags); 667 dest.writeInt(mLaunchMode); 668 dest.writeBoolean(mWasForceStopped); 669 } 670 671 /** @hide */ ApplicationStartInfo()672 public ApplicationStartInfo() {} 673 674 /** @hide */ ApplicationStartInfo(ApplicationStartInfo other)675 public ApplicationStartInfo(ApplicationStartInfo other) { 676 mStartupState = other.mStartupState; 677 mPid = other.mPid; 678 mRealUid = other.mRealUid; 679 mPackageUid = other.mPackageUid; 680 mDefiningUid = other.mDefiningUid; 681 mPackageName = other.mPackageName; 682 mProcessName = other.mProcessName; 683 mReason = other.mReason; 684 mStartupTimestampsNs = other.mStartupTimestampsNs; 685 mStartType = other.mStartType; 686 mStartIntent = other.mStartIntent; 687 mLaunchMode = other.mLaunchMode; 688 mWasForceStopped = other.mWasForceStopped; 689 } 690 ApplicationStartInfo(@onNull Parcel in)691 private ApplicationStartInfo(@NonNull Parcel in) { 692 mStartupState = in.readInt(); 693 mPid = in.readInt(); 694 mRealUid = in.readInt(); 695 mPackageUid = in.readInt(); 696 mDefiningUid = in.readInt(); 697 mPackageName = intern(in.readString()); 698 mProcessName = intern(in.readString()); 699 mReason = in.readInt(); 700 int starupTimestampCount = in.readInt(); 701 for (int i = 0; i < starupTimestampCount; i++) { 702 int key = in.readInt(); 703 long val = in.readLong(); 704 addStartupTimestamp(key, val); 705 } 706 mStartType = in.readInt(); 707 mStartIntent = 708 in.readParcelable(Intent.class.getClassLoader(), android.content.Intent.class); 709 mLaunchMode = in.readInt(); 710 mWasForceStopped = in.readBoolean(); 711 } 712 intern(@ullable String source)713 private static String intern(@Nullable String source) { 714 return source != null ? source.intern() : null; 715 } 716 717 public @NonNull static final Creator<ApplicationStartInfo> CREATOR = 718 new Creator<ApplicationStartInfo>() { 719 @Override 720 public ApplicationStartInfo createFromParcel(Parcel in) { 721 return new ApplicationStartInfo(in); 722 } 723 724 @Override 725 public ApplicationStartInfo[] newArray(int size) { 726 return new ApplicationStartInfo[size]; 727 } 728 }; 729 730 private static final String PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS = "timestamps"; 731 private static final String PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP = "timestamp"; 732 private static final String PROTO_SERIALIZER_ATTRIBUTE_KEY = "key"; 733 private static final String PROTO_SERIALIZER_ATTRIBUTE_TS = "ts"; 734 private static final String PROTO_SERIALIZER_ATTRIBUTE_INTENT = "intent"; 735 736 /** 737 * Write to a protocol buffer output stream. Protocol buffer message definition at {@link 738 * android.app.ApplicationStartInfoProto} 739 * 740 * @param proto Stream to write the ApplicationStartInfo object to. 741 * @param fieldId Field Id of the ApplicationStartInfo as defined in the parent message 742 * @hide 743 */ writeToProto(ProtoOutputStream proto, long fieldId)744 public void writeToProto(ProtoOutputStream proto, long fieldId) throws IOException { 745 final long token = proto.start(fieldId); 746 proto.write(ApplicationStartInfoProto.PID, mPid); 747 proto.write(ApplicationStartInfoProto.REAL_UID, mRealUid); 748 proto.write(ApplicationStartInfoProto.PACKAGE_UID, mPackageUid); 749 proto.write(ApplicationStartInfoProto.DEFINING_UID, mDefiningUid); 750 proto.write(ApplicationStartInfoProto.PROCESS_NAME, mProcessName); 751 proto.write(ApplicationStartInfoProto.STARTUP_STATE, mStartupState); 752 proto.write(ApplicationStartInfoProto.REASON, mReason); 753 if (mStartupTimestampsNs != null && mStartupTimestampsNs.size() > 0) { 754 ByteArrayOutputStream timestampsBytes = new ByteArrayOutputStream(); 755 ObjectOutputStream timestampsOut = new ObjectOutputStream(timestampsBytes); 756 TypedXmlSerializer serializer = Xml.resolveSerializer(timestampsOut); 757 serializer.startDocument(null, true); 758 serializer.startTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS); 759 for (int i = 0; i < mStartupTimestampsNs.size(); i++) { 760 serializer.startTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP); 761 serializer.attributeInt(null, PROTO_SERIALIZER_ATTRIBUTE_KEY, 762 mStartupTimestampsNs.keyAt(i)); 763 serializer.attributeLong(null, PROTO_SERIALIZER_ATTRIBUTE_TS, 764 mStartupTimestampsNs.valueAt(i)); 765 serializer.endTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP); 766 } 767 serializer.endTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS); 768 serializer.endDocument(); 769 proto.write(ApplicationStartInfoProto.STARTUP_TIMESTAMPS, 770 timestampsBytes.toByteArray()); 771 timestampsOut.close(); 772 } 773 proto.write(ApplicationStartInfoProto.START_TYPE, mStartType); 774 if (mStartIntent != null) { 775 ByteArrayOutputStream intentBytes = new ByteArrayOutputStream(); 776 ObjectOutputStream intentOut = new ObjectOutputStream(intentBytes); 777 TypedXmlSerializer serializer = Xml.resolveSerializer(intentOut); 778 serializer.startDocument(null, true); 779 serializer.startTag(null, PROTO_SERIALIZER_ATTRIBUTE_INTENT); 780 mStartIntent.saveToXml(serializer); 781 serializer.endTag(null, PROTO_SERIALIZER_ATTRIBUTE_INTENT); 782 serializer.endDocument(); 783 proto.write(ApplicationStartInfoProto.START_INTENT, 784 intentBytes.toByteArray()); 785 intentOut.close(); 786 } 787 proto.write(ApplicationStartInfoProto.LAUNCH_MODE, mLaunchMode); 788 proto.write(ApplicationStartInfoProto.WAS_FORCE_STOPPED, mWasForceStopped); 789 proto.end(token); 790 } 791 792 /** 793 * Read from a protocol buffer input stream. Protocol buffer message definition at {@link 794 * android.app.ApplicationStartInfoProto} 795 * 796 * @param proto Stream to read the ApplicationStartInfo object from. 797 * @param fieldId Field Id of the ApplicationStartInfo as defined in the parent message 798 * @hide 799 */ readFromProto(ProtoInputStream proto, long fieldId)800 public void readFromProto(ProtoInputStream proto, long fieldId) 801 throws IOException, WireTypeMismatchException, ClassNotFoundException { 802 final long token = proto.start(fieldId); 803 while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) { 804 switch (proto.getFieldNumber()) { 805 case (int) ApplicationStartInfoProto.PID: 806 mPid = proto.readInt(ApplicationStartInfoProto.PID); 807 break; 808 case (int) ApplicationStartInfoProto.REAL_UID: 809 mRealUid = proto.readInt(ApplicationStartInfoProto.REAL_UID); 810 break; 811 case (int) ApplicationStartInfoProto.PACKAGE_UID: 812 mPackageUid = proto.readInt(ApplicationStartInfoProto.PACKAGE_UID); 813 break; 814 case (int) ApplicationStartInfoProto.DEFINING_UID: 815 mDefiningUid = proto.readInt(ApplicationStartInfoProto.DEFINING_UID); 816 break; 817 case (int) ApplicationStartInfoProto.PROCESS_NAME: 818 mProcessName = intern(proto.readString(ApplicationStartInfoProto.PROCESS_NAME)); 819 break; 820 case (int) ApplicationStartInfoProto.STARTUP_STATE: 821 mStartupState = proto.readInt(ApplicationStartInfoProto.STARTUP_STATE); 822 break; 823 case (int) ApplicationStartInfoProto.REASON: 824 mReason = proto.readInt(ApplicationStartInfoProto.REASON); 825 break; 826 case (int) ApplicationStartInfoProto.STARTUP_TIMESTAMPS: 827 ByteArrayInputStream timestampsBytes = new ByteArrayInputStream(proto.readBytes( 828 ApplicationStartInfoProto.STARTUP_TIMESTAMPS)); 829 ObjectInputStream timestampsIn = new ObjectInputStream(timestampsBytes); 830 mStartupTimestampsNs = new ArrayMap<Integer, Long>(); 831 try { 832 TypedXmlPullParser parser = Xml.resolvePullParser(timestampsIn); 833 XmlUtils.beginDocument(parser, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS); 834 int depth = parser.getDepth(); 835 while (XmlUtils.nextElementWithin(parser, depth)) { 836 if (PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP.equals(parser.getName())) { 837 int key = parser.getAttributeInt(null, 838 PROTO_SERIALIZER_ATTRIBUTE_KEY); 839 long ts = parser.getAttributeLong(null, 840 PROTO_SERIALIZER_ATTRIBUTE_TS); 841 mStartupTimestampsNs.put(key, ts); 842 } 843 } 844 } catch (XmlPullParserException e) { 845 // Timestamps lost 846 } 847 timestampsIn.close(); 848 break; 849 case (int) ApplicationStartInfoProto.START_TYPE: 850 mStartType = proto.readInt(ApplicationStartInfoProto.START_TYPE); 851 break; 852 case (int) ApplicationStartInfoProto.START_INTENT: 853 ByteArrayInputStream intentBytes = new ByteArrayInputStream(proto.readBytes( 854 ApplicationStartInfoProto.START_INTENT)); 855 ObjectInputStream intentIn = new ObjectInputStream(intentBytes); 856 try { 857 TypedXmlPullParser parser = Xml.resolvePullParser(intentIn); 858 XmlUtils.beginDocument(parser, PROTO_SERIALIZER_ATTRIBUTE_INTENT); 859 mStartIntent = Intent.restoreFromXml(parser); 860 } catch (XmlPullParserException e) { 861 // Intent lost 862 } 863 intentIn.close(); 864 break; 865 case (int) ApplicationStartInfoProto.LAUNCH_MODE: 866 mLaunchMode = proto.readInt(ApplicationStartInfoProto.LAUNCH_MODE); 867 break; 868 case (int) ApplicationStartInfoProto.WAS_FORCE_STOPPED: 869 mWasForceStopped = proto.readBoolean( 870 ApplicationStartInfoProto.WAS_FORCE_STOPPED); 871 break; 872 } 873 } 874 proto.end(token); 875 } 876 877 /** @hide */ dump(@onNull PrintWriter pw, @Nullable String prefix, @Nullable String seqSuffix, @NonNull SimpleDateFormat sdf)878 public void dump(@NonNull PrintWriter pw, @Nullable String prefix, @Nullable String seqSuffix, 879 @NonNull SimpleDateFormat sdf) { 880 StringBuilder sb = new StringBuilder(); 881 sb.append(prefix) 882 .append("ApplicationStartInfo ").append(seqSuffix).append(':') 883 .append('\n') 884 .append(" pid=").append(mPid) 885 .append(" realUid=").append(mRealUid) 886 .append(" packageUid=").append(mPackageUid) 887 .append(" definingUid=").append(mDefiningUid) 888 .append(" user=").append(UserHandle.getUserId(mPackageUid)) 889 .append('\n') 890 .append(" package=").append(mPackageName) 891 .append(" process=").append(mProcessName) 892 .append(" startupState=").append(mStartupState) 893 .append(" reason=").append(reasonToString(mReason)) 894 .append(" startType=").append(startTypeToString(mStartType)) 895 .append(" launchMode=").append(mLaunchMode) 896 .append(" wasForceStopped=").append(mWasForceStopped) 897 .append('\n'); 898 if (mStartIntent != null) { 899 sb.append(" intent=").append(mStartIntent.toString()) 900 .append('\n'); 901 } 902 if (mStartupTimestampsNs != null && mStartupTimestampsNs.size() > 0) { 903 sb.append(" timestamps: "); 904 for (int i = 0; i < mStartupTimestampsNs.size(); i++) { 905 sb.append(mStartupTimestampsNs.keyAt(i)).append("=").append(mStartupTimestampsNs 906 .valueAt(i)).append(" "); 907 } 908 sb.append('\n'); 909 } 910 pw.print(sb.toString()); 911 } 912 reasonToString(@tartReason int reason)913 private static String reasonToString(@StartReason int reason) { 914 return switch (reason) { 915 case START_REASON_ALARM -> "ALARM"; 916 case START_REASON_BACKUP -> "BACKUP"; 917 case START_REASON_BOOT_COMPLETE -> "BOOT COMPLETE"; 918 case START_REASON_BROADCAST -> "BROADCAST"; 919 case START_REASON_CONTENT_PROVIDER -> "CONTENT PROVIDER"; 920 case START_REASON_JOB -> "JOB"; 921 case START_REASON_LAUNCHER -> "LAUNCHER"; 922 case START_REASON_LAUNCHER_RECENTS -> "LAUNCHER RECENTS"; 923 case START_REASON_OTHER -> "OTHER"; 924 case START_REASON_PUSH -> "PUSH"; 925 case START_REASON_SERVICE -> "SERVICE"; 926 case START_REASON_START_ACTIVITY -> "START ACTIVITY"; 927 default -> ""; 928 }; 929 } 930 startTypeToString(@tartType int startType)931 private static String startTypeToString(@StartType int startType) { 932 return switch (startType) { 933 case START_TYPE_UNSET -> "UNSET"; 934 case START_TYPE_COLD -> "COLD"; 935 case START_TYPE_WARM -> "WARM"; 936 case START_TYPE_HOT -> "HOT"; 937 default -> ""; 938 }; 939 } 940 941 /** @hide */ 942 @Override 943 public boolean equals(@Nullable Object other) { 944 if (other == null || !(other instanceof ApplicationStartInfo)) { 945 return false; 946 } 947 final ApplicationStartInfo o = (ApplicationStartInfo) other; 948 return mPid == o.mPid && mRealUid == o.mRealUid && mPackageUid == o.mPackageUid 949 && mDefiningUid == o.mDefiningUid && mReason == o.mReason 950 && mStartupState == o.mStartupState && mStartType == o.mStartType 951 && mLaunchMode == o.mLaunchMode && TextUtils.equals(mProcessName, o.mProcessName) 952 && timestampsEquals(o) && mWasForceStopped == o.mWasForceStopped; 953 } 954 955 @Override 956 public int hashCode() { 957 return Objects.hash(mPid, mRealUid, mPackageUid, mDefiningUid, mReason, mStartupState, 958 mStartType, mLaunchMode, mProcessName, 959 mStartupTimestampsNs); 960 } 961 962 private boolean timestampsEquals(@NonNull ApplicationStartInfo other) { 963 if (mStartupTimestampsNs == null && other.mStartupTimestampsNs == null) { 964 return true; 965 } 966 if (mStartupTimestampsNs == null || other.mStartupTimestampsNs == null) { 967 return false; 968 } 969 return mStartupTimestampsNs.equals(other.mStartupTimestampsNs); 970 } 971 } 972