diff options
3 files changed, 68 insertions, 9 deletions
diff --git a/core/java/android/app/ApplicationStartInfo.java b/core/java/android/app/ApplicationStartInfo.java index edcdb6cc58ea..f34341fd14e1 100644 --- a/core/java/android/app/ApplicationStartInfo.java +++ b/core/java/android/app/ApplicationStartInfo.java @@ -34,6 +34,7 @@ import android.util.proto.ProtoInputStream; import android.util.proto.ProtoOutputStream; import android.util.proto.WireTypeMismatchException; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.XmlUtils; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; @@ -777,7 +778,9 @@ public final class ApplicationStartInfo implements Parcelable { mStartComponent = other.mStartComponent; } - private ApplicationStartInfo(@NonNull Parcel in) { + /** @hide */ + @VisibleForTesting + public ApplicationStartInfo(@NonNull Parcel in) { mStartupState = in.readInt(); mPid = in.readInt(); mRealUid = in.readInt(); @@ -1061,12 +1064,21 @@ public final class ApplicationStartInfo implements Parcelable { if (other == null || !(other instanceof ApplicationStartInfo)) { return false; } + final ApplicationStartInfo o = (ApplicationStartInfo) other; - return mPid == o.mPid && mRealUid == o.mRealUid && mPackageUid == o.mPackageUid - && mDefiningUid == o.mDefiningUid && mReason == o.mReason - && mStartupState == o.mStartupState && mStartType == o.mStartType - && mLaunchMode == o.mLaunchMode && TextUtils.equals(mProcessName, o.mProcessName) - && timestampsEquals(o) && mWasForceStopped == o.mWasForceStopped + + return mPid == o.mPid + && mRealUid == o.mRealUid + && mPackageUid == o.mPackageUid + && mDefiningUid == o.mDefiningUid + && mReason == o.mReason + && mStartupState == o.mStartupState + && mStartType == o.mStartType + && mLaunchMode == o.mLaunchMode + && TextUtils.equals(mPackageName, o.mPackageName) + && TextUtils.equals(mProcessName, o.mProcessName) + && timestampsEquals(o) + && mWasForceStopped == o.mWasForceStopped && mMonoticCreationTimeMs == o.mMonoticCreationTimeMs && mStartComponent == o.mStartComponent; } @@ -1074,7 +1086,7 @@ public final class ApplicationStartInfo implements Parcelable { @Override public int hashCode() { return Objects.hash(mPid, mRealUid, mPackageUid, mDefiningUid, mReason, mStartupState, - mStartType, mLaunchMode, mProcessName, mStartupTimestampsNs, + mStartType, mLaunchMode, mPackageName, mProcessName, mStartupTimestampsNs, mMonoticCreationTimeMs, mStartComponent); } diff --git a/services/core/java/com/android/server/am/AppStartInfoTracker.java b/services/core/java/com/android/server/am/AppStartInfoTracker.java index 71b64567d062..aca6d0b0b967 100644 --- a/services/core/java/com/android/server/am/AppStartInfoTracker.java +++ b/services/core/java/com/android/server/am/AppStartInfoTracker.java @@ -1005,7 +1005,8 @@ public final class AppStartInfoTracker { case (int) AppsStartInfoProto.Package.USERS: AppStartInfoContainer container = new AppStartInfoContainer(mAppStartInfoHistoryListSize); - int uid = container.readFromProto(proto, AppsStartInfoProto.Package.USERS); + int uid = container.readFromProto(proto, AppsStartInfoProto.Package.USERS, + pkgName); synchronized (mLock) { mData.put(pkgName, uid, container); } @@ -1403,7 +1404,7 @@ public final class AppStartInfoTracker { proto.end(token); } - int readFromProto(ProtoInputStream proto, long fieldId) + int readFromProto(ProtoInputStream proto, long fieldId, String packageName) throws IOException, WireTypeMismatchException, ClassNotFoundException { long token = proto.start(fieldId); for (int next = proto.nextField(); @@ -1418,6 +1419,7 @@ public final class AppStartInfoTracker { // have a create time. ApplicationStartInfo info = new ApplicationStartInfo(0); info.readFromProto(proto, AppsStartInfoProto.Package.User.APP_START_INFO); + info.setPackageName(packageName); mInfos.add(info); break; case (int) AppsStartInfoProto.Package.User.MONITORING_ENABLED: diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java index e863f1574932..e678acc092e9 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java @@ -39,6 +39,7 @@ import android.content.pm.PackageManagerInternal; import android.os.FileUtils; import android.os.Handler; import android.os.HandlerThread; +import android.os.Parcel; import android.os.Process; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; @@ -580,6 +581,50 @@ public class ApplicationStartInfoTest { assertTrue(mAppStartInfoTracker.mMonotonicClock.monotonicTime() >= originalMonotonicTime); } + /** + * Test to confirm that parcel read and write implementations match, correctly loading records + * with the same values and leaving no data unread. + */ + @Test + public void testParcelReadWriteMatch() throws Exception { + // Create a start info records with all fields set. + ApplicationStartInfo startInfo = new ApplicationStartInfo(1234L); + startInfo.setPid(123); + startInfo.setRealUid(987); + startInfo.setPackageUid(654); + startInfo.setDefiningUid(321); + startInfo.setReason(ApplicationStartInfo.START_REASON_LAUNCHER); + startInfo.setStartupState(ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN); + startInfo.setStartType(ApplicationStartInfo.START_TYPE_WARM); + startInfo.setLaunchMode(ApplicationStartInfo.LAUNCH_MODE_SINGLE_TOP); + startInfo.setPackageName(APP_1_PACKAGE_NAME); + startInfo.setProcessName(APP_1_PROCESS_NAME); + startInfo.addStartupTimestamp(ApplicationStartInfo.START_TIMESTAMP_LAUNCH, 999L); + startInfo.addStartupTimestamp(ApplicationStartInfo.START_TIMESTAMP_FIRST_FRAME, 888L); + startInfo.setForceStopped(true); + startInfo.setStartComponent(ApplicationStartInfo.START_COMPONENT_OTHER); + startInfo.setIntent(buildIntent(COMPONENT)); + + // Write the start info to a parcel. + Parcel parcel = Parcel.obtain(); + startInfo.writeToParcel(parcel, 0 /* flags */); + + // Set the data position back to 0 so it's ready to be read. + parcel.setDataPosition(0); + + // Now load the record from the parcel. + ApplicationStartInfo startInfoFromParcel = new ApplicationStartInfo(parcel); + + // Make sure there is no unread data remaining in the parcel, and confirm that the loaded + // start info object is equal to the one it was written from. Check dataAvail first as if + // that check fails then the next check will fail too, but knowing the status of this check + // will tell us that we're missing a read or write. Check the objects are equals second as + // if the avail check passes and equals fails, then we know we're reading all the data just + // not to the correct fields. + assertEquals(0, parcel.dataAvail()); + assertTrue(startInfo.equals(startInfoFromParcel)); + } + private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) { try { Field field = clazz.getDeclaredField(fieldName); |