From e4b3ff67a63bb218f0001d9d170025d86974b7fe Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Thu, 17 Dec 2020 17:05:46 +0800 Subject: [PATCH] Send ActivityOptions to client This removes getActivityOptions from server side. So 2 binder transactions from Activity#performCreate and performStart can be eliminated. The remote animation in ActivityOptions is also separated to another field of ActivityRecord, so when consuming the options, the remote animation won't be affected. Bug: 65202329 Bug: 132432864 Bug: 175409544 Test: WmTests:ActivityRecordTests#testTakeOptions ObjectPoolTests#testRecycleStartActivityItem CtsTransitionTestCases:ActivityTransitionTest CtsUsageStatsTestCases:ActivityTransitionTest Change-Id: I600a9a478a3e596e58b0a8120cfa8b9f32598b47 --- core/java/android/app/Activity.java | 10 +- core/java/android/app/ActivityClient.java | 8 -- core/java/android/app/ActivityThread.java | 17 ++- .../android/app/ClientTransactionHandler.java | 2 +- .../app/IActivityClientController.aidl | 1 - .../android/app/LocalActivityManager.java | 3 +- .../servertransaction/LaunchActivityItem.java | 34 +++-- .../servertransaction/StartActivityItem.java | 22 ++-- .../TransactionExecutor.java | 3 +- .../TransactionExecutorHelper.java | 2 +- .../servertransaction/ObjectPoolTests.java | 18 +++ .../app/servertransaction/TestUtils.java | 11 +- .../TransactionParcelTests.java | 10 +- .../activity/ActivityThreadClientTest.java | 7 +- .../server/wm/ActivityClientController.java | 18 --- .../com/android/server/wm/ActivityRecord.java | 118 ++++++++++-------- .../server/wm/ActivityStartController.java | 2 +- .../android/server/wm/ActivityStarter.java | 2 +- .../server/wm/ActivityTaskSupervisor.java | 11 +- .../server/wm/ResetTargetTaskHelper.java | 3 +- .../core/java/com/android/server/wm/Task.java | 9 +- .../server/wm/ActivityRecordTests.java | 30 ++--- 22 files changed, 198 insertions(+), 143 deletions(-) diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 294a363bc52f9..55df824b12436 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -890,6 +890,9 @@ public class Activity extends ContextThemeWrapper @UnsupportedAppUsage final FragmentController mFragments = FragmentController.createController(new HostCallbacks()); + /** The options for scene transition. */ + ActivityOptions mPendingOptions; + private static final class ManagedCursor { ManagedCursor(Cursor cursor) { mCursor = cursor; @@ -7258,7 +7261,7 @@ public class Activity extends ContextThemeWrapper } /** - * Retrieve the ActivityOptions passed in from the launching activity or passed back + * Takes the ActivityOptions passed in from the launching activity or passed back * from an activity launched by this activity in its call to {@link * #convertToTranslucent(TranslucentConversionListener, ActivityOptions)} * @@ -7267,7 +7270,10 @@ public class Activity extends ContextThemeWrapper */ @UnsupportedAppUsage ActivityOptions getActivityOptions() { - return ActivityOptions.fromBundle(ActivityClient.getInstance().getActivityOptions(mToken)); + final ActivityOptions options = mPendingOptions; + // The option only applies once. + mPendingOptions = null; + return options; } /** diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java index 64d795c013c90..d465b220f8546 100644 --- a/core/java/android/app/ActivityClient.java +++ b/core/java/android/app/ActivityClient.java @@ -237,14 +237,6 @@ public class ActivityClient { } } - Bundle getActivityOptions(IBinder token) { - try { - return getActivityClientController().getActivityOptions(token); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - public void setRequestedOrientation(IBinder token, int requestedOrientation) { try { getActivityClientController().setRequestedOrientation(token, requestedOrientation); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 69482bc8615ba..2fe1711bdbd4f 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -567,6 +567,9 @@ public final class ActivityThread extends ClientTransactionHandler { @UnsupportedAppUsage boolean mPreserveWindow; + /** The options for scene transition. */ + ActivityOptions mActivityOptions; + /** * If non-null, the activity is launching with a specified rotation, the adjustments should * be consumed before activity creation. @@ -587,8 +590,8 @@ public final class ActivityThread extends ClientTransactionHandler { ActivityInfo info, Configuration overrideConfig, CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor, Bundle state, PersistableBundle persistentState, List pendingResults, - List pendingNewIntents, boolean isForward, - ProfilerInfo profilerInfo, ClientTransactionHandler client, + List pendingNewIntents, ActivityOptions activityOptions, + boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client, IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments) { this.token = token; this.assistToken = assistToken; @@ -607,6 +610,7 @@ public final class ActivityThread extends ClientTransactionHandler { this.overrideConfig = overrideConfig; this.packageInfo = client.getPackageInfoNoCheck(activityInfo.applicationInfo, compatInfo); + mActivityOptions = activityOptions; mPendingFixedRotationAdjustments = fixedRotationAdjustments; init(); } @@ -3469,6 +3473,10 @@ public final class ActivityThread extends ClientTransactionHandler { activity.setTheme(theme); } + if (r.mActivityOptions != null) { + activity.mPendingOptions = r.mActivityOptions; + r.mActivityOptions = null; + } activity.mCalled = false; if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); @@ -3509,7 +3517,7 @@ public final class ActivityThread extends ClientTransactionHandler { @Override public void handleStartActivity(ActivityClientRecord r, - PendingTransactionActions pendingActions) { + PendingTransactionActions pendingActions, ActivityOptions activityOptions) { final Activity activity = r.activity; if (!r.stopped) { throw new IllegalStateException("Can't start activity that is not stopped."); @@ -3520,6 +3528,9 @@ public final class ActivityThread extends ClientTransactionHandler { } unscheduleGcIdler(); + if (activityOptions != null) { + activity.mPendingOptions = activityOptions; + } // Start activity.performStart("handleStartActivity"); diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java index ac50676ff46b8..0e1c827145d2d 100644 --- a/core/java/android/app/ClientTransactionHandler.java +++ b/core/java/android/app/ClientTransactionHandler.java @@ -164,7 +164,7 @@ public abstract class ClientTransactionHandler { /** Perform activity start. */ public abstract void handleStartActivity(@NonNull ActivityClientRecord r, - PendingTransactionActions pendingActions); + PendingTransactionActions pendingActions, ActivityOptions activityOptions); /** Get package info. */ public abstract LoadedApk getPackageInfoNoCheck(ApplicationInfo ai, diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl index e1e0a8a534a82..b9a203c3f0ba8 100644 --- a/core/java/android/app/IActivityClientController.aidl +++ b/core/java/android/app/IActivityClientController.aidl @@ -60,7 +60,6 @@ interface IActivityClientController { String getCallingPackage(in IBinder token); int getLaunchedFromUid(in IBinder token); String getLaunchedFromPackage(in IBinder token); - Bundle getActivityOptions(in IBinder token); void setRequestedOrientation(in IBinder token, int requestedOrientation); int getRequestedOrientation(in IBinder token); diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java index 2e7c9f11ac66b..74e61250f1099 100644 --- a/core/java/android/app/LocalActivityManager.java +++ b/core/java/android/app/LocalActivityManager.java @@ -178,7 +178,8 @@ public class LocalActivityManager { pendingActions = null; } - mActivityThread.handleStartActivity(clientRecord, pendingActions); + mActivityThread.handleStartActivity(clientRecord, pendingActions, + null /* activityOptions */); r.curState = STARTED; if (desiredState == RESUMED) { diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java index 3758cb49e2d0e..73a9cecceceef 100644 --- a/core/java/android/app/servertransaction/LaunchActivityItem.java +++ b/core/java/android/app/servertransaction/LaunchActivityItem.java @@ -21,6 +21,7 @@ import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityClient; +import android.app.ActivityOptions; import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.app.IActivityClientController; @@ -66,6 +67,7 @@ public class LaunchActivityItem extends ClientTransactionItem { private PersistableBundle mPersistentState; private List mPendingResults; private List mPendingNewIntents; + private ActivityOptions mActivityOptions; private boolean mIsForward; private ProfilerInfo mProfilerInfo; private IBinder mAssistToken; @@ -92,8 +94,8 @@ public class LaunchActivityItem extends ClientTransactionItem { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo, mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState, - mPendingResults, mPendingNewIntents, mIsForward, - mProfilerInfo, client, mAssistToken, mFixedRotationAdjustments); + mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo, + client, mAssistToken, mFixedRotationAdjustments); client.handleLaunchActivity(r, pendingActions, null /* customIntent */); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -114,8 +116,9 @@ public class LaunchActivityItem extends ClientTransactionItem { Configuration curConfig, Configuration overrideConfig, CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state, PersistableBundle persistentState, List pendingResults, - List pendingNewIntents, boolean isForward, ProfilerInfo profilerInfo, - IBinder assistToken, IActivityClientController activityClientController, + List pendingNewIntents, ActivityOptions activityOptions, + boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken, + IActivityClientController activityClientController, FixedRotationAdjustments fixedRotationAdjustments) { LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class); if (instance == null) { @@ -123,8 +126,8 @@ public class LaunchActivityItem extends ClientTransactionItem { } setValues(instance, intent, ident, info, curConfig, overrideConfig, compatInfo, referrer, voiceInteractor, procState, state, persistentState, pendingResults, - pendingNewIntents, isForward, profilerInfo, assistToken, activityClientController, - fixedRotationAdjustments); + pendingNewIntents, activityOptions, isForward, profilerInfo, assistToken, + activityClientController, fixedRotationAdjustments); return instance; } @@ -132,7 +135,7 @@ public class LaunchActivityItem extends ClientTransactionItem { @Override public void recycle() { setValues(this, null, 0, null, null, null, null, null, null, 0, null, null, null, null, - false, null, null, null, null); + null, false, null, null, null, null); ObjectPool.recycle(this); } @@ -155,6 +158,7 @@ public class LaunchActivityItem extends ClientTransactionItem { dest.writePersistableBundle(mPersistentState); dest.writeTypedList(mPendingResults, flags); dest.writeTypedList(mPendingNewIntents, flags); + dest.writeBundle(mActivityOptions != null ? mActivityOptions.toBundle() : null); dest.writeBoolean(mIsForward); dest.writeTypedObject(mProfilerInfo, flags); dest.writeStrongBinder(mAssistToken); @@ -172,7 +176,8 @@ public class LaunchActivityItem extends ClientTransactionItem { in.readBundle(getClass().getClassLoader()), in.readPersistableBundle(getClass().getClassLoader()), in.createTypedArrayList(ResultInfo.CREATOR), - in.createTypedArrayList(ReferrerIntent.CREATOR), in.readBoolean(), + in.createTypedArrayList(ReferrerIntent.CREATOR), + ActivityOptions.fromBundle(in.readBundle()), in.readBoolean(), in.readTypedObject(ProfilerInfo.CREATOR), in.readStrongBinder(), IActivityClientController.Stub.asInterface(in.readStrongBinder()), @@ -210,6 +215,7 @@ public class LaunchActivityItem extends ClientTransactionItem { && areBundlesEqualRoughly(mPersistentState, other.mPersistentState) && Objects.equals(mPendingResults, other.mPendingResults) && Objects.equals(mPendingNewIntents, other.mPendingNewIntents) + && (mActivityOptions == null) == (other.mActivityOptions == null) && mIsForward == other.mIsForward && Objects.equals(mProfilerInfo, other.mProfilerInfo) && Objects.equals(mAssistToken, other.mAssistToken) @@ -230,6 +236,7 @@ public class LaunchActivityItem extends ClientTransactionItem { result = 31 * result + getRoughBundleHashCode(mPersistentState); result = 31 * result + Objects.hashCode(mPendingResults); result = 31 * result + Objects.hashCode(mPendingNewIntents); + result = 31 * result + (mActivityOptions != null ? 1 : 0); result = 31 * result + (mIsForward ? 1 : 0); result = 31 * result + Objects.hashCode(mProfilerInfo); result = 31 * result + Objects.hashCode(mAssistToken); @@ -268,9 +275,9 @@ public class LaunchActivityItem extends ClientTransactionItem { + ",curConfig=" + mCurConfig + ",overrideConfig=" + mOverrideConfig + ",referrer=" + mReferrer + ",procState=" + mProcState + ",state=" + mState + ",persistentState=" + mPersistentState + ",pendingResults=" + mPendingResults - + ",pendingNewIntents=" + mPendingNewIntents + ",profilerInfo=" + mProfilerInfo - + ",assistToken=" + mAssistToken + ",rotationAdj=" + mFixedRotationAdjustments - + "}"; + + ",pendingNewIntents=" + mPendingNewIntents + ",options=" + mActivityOptions + + ",profilerInfo=" + mProfilerInfo + ",assistToken=" + mAssistToken + + ",rotationAdj=" + mFixedRotationAdjustments + "}"; } // Using the same method to set and clear values to make sure we don't forget anything @@ -279,8 +286,8 @@ public class LaunchActivityItem extends ClientTransactionItem { CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state, PersistableBundle persistentState, List pendingResults, List pendingNewIntents, - boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken, - IActivityClientController activityClientController, + ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo, + IBinder assistToken, IActivityClientController activityClientController, FixedRotationAdjustments fixedRotationAdjustments) { instance.mIntent = intent; instance.mIdent = ident; @@ -295,6 +302,7 @@ public class LaunchActivityItem extends ClientTransactionItem { instance.mPersistentState = persistentState; instance.mPendingResults = pendingResults; instance.mPendingNewIntents = pendingNewIntents; + instance.mActivityOptions = activityOptions; instance.mIsForward = isForward; instance.mProfilerInfo = profilerInfo; instance.mAssistToken = assistToken; diff --git a/core/java/android/app/servertransaction/StartActivityItem.java b/core/java/android/app/servertransaction/StartActivityItem.java index 483f9de58a1c4..15f65f6d9d26b 100644 --- a/core/java/android/app/servertransaction/StartActivityItem.java +++ b/core/java/android/app/servertransaction/StartActivityItem.java @@ -20,6 +20,7 @@ import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityOptions; import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.os.Parcel; @@ -33,11 +34,13 @@ public class StartActivityItem extends ActivityLifecycleItem { private static final String TAG = "StartActivityItem"; + private ActivityOptions mActivityOptions; + @Override public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "startActivityItem"); - client.handleStartActivity(r, pendingActions); + client.handleStartActivity(r, pendingActions, mActivityOptions); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -52,11 +55,12 @@ public class StartActivityItem extends ActivityLifecycleItem { private StartActivityItem() {} /** Obtain an instance initialized with provided params. */ - public static StartActivityItem obtain() { + public static StartActivityItem obtain(ActivityOptions activityOptions) { StartActivityItem instance = ObjectPool.obtain(StartActivityItem.class); if (instance == null) { instance = new StartActivityItem(); } + instance.mActivityOptions = activityOptions; return instance; } @@ -64,6 +68,7 @@ public class StartActivityItem extends ActivityLifecycleItem { @Override public void recycle() { super.recycle(); + mActivityOptions = null; ObjectPool.recycle(this); } @@ -73,12 +78,12 @@ public class StartActivityItem extends ActivityLifecycleItem { /** Write to Parcel. */ @Override public void writeToParcel(Parcel dest, int flags) { - // Empty + dest.writeBundle(mActivityOptions != null ? mActivityOptions.toBundle() : null); } /** Read from Parcel. */ private StartActivityItem(Parcel in) { - // Empty + mActivityOptions = ActivityOptions.fromBundle(in.readBundle()); } public static final @NonNull Creator CREATOR = @@ -100,17 +105,20 @@ public class StartActivityItem extends ActivityLifecycleItem { if (o == null || getClass() != o.getClass()) { return false; } - return true; + final StartActivityItem other = (StartActivityItem) o; + return (mActivityOptions == null) == (other.mActivityOptions == null); } @Override public int hashCode() { - return 17; + int result = 17; + result = 31 * result + (mActivityOptions != null ? 1 : 0); + return result; } @Override public String toString() { - return "StartActivityItem{}"; + return "StartActivityItem{options=" + mActivityOptions + "}"; } } diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java index 3dcf2cb5f13ed..25ff8a78a0c82 100644 --- a/core/java/android/app/servertransaction/TransactionExecutor.java +++ b/core/java/android/app/servertransaction/TransactionExecutor.java @@ -218,7 +218,8 @@ public class TransactionExecutor { null /* customIntent */); break; case ON_START: - mTransactionHandler.handleStartActivity(r, mPendingActions); + mTransactionHandler.handleStartActivity(r, mPendingActions, + null /* activityOptions */); break; case ON_RESUME: mTransactionHandler.handleResumeActivity(r, false /* finalStateRequest */, diff --git a/core/java/android/app/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java index 56bf59b52f745..92f7dee0b0add 100644 --- a/core/java/android/app/servertransaction/TransactionExecutorHelper.java +++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java @@ -186,7 +186,7 @@ public class TransactionExecutorHelper { switch (prevState) { // TODO(lifecycler): Extend to support all possible states. case ON_START: - lifecycleItem = StartActivityItem.obtain(); + lifecycleItem = StartActivityItem.obtain(null /* activityOptions */); break; case ON_PAUSE: lifecycleItem = PauseActivityItem.obtain(); diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java index b2b34d64b12c4..50b52eb2a0eae 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java @@ -23,9 +23,11 @@ import static android.app.servertransaction.TestUtils.resultInfoList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; +import android.app.ActivityOptions; import android.app.servertransaction.TestUtils.LaunchActivityItemBuilder; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -246,6 +248,22 @@ public class ObjectPoolTests { assertFalse(item2.equals(emptyItem)); } + @Test + public void testRecycleStartActivityItem() { + StartActivityItem emptyItem = StartActivityItem.obtain(null /* activityOptions */); + StartActivityItem item = StartActivityItem.obtain(ActivityOptions.makeBasic()); + assertNotSame(item, emptyItem); + assertNotEquals(item, emptyItem); + + item.recycle(); + assertEquals(item, emptyItem); + + StartActivityItem item2 = StartActivityItem.obtain( + ActivityOptions.makeBasic().setLaunchDisplayId(10)); + assertSame(item, item2); + assertNotEquals(item2, emptyItem); + } + @Test public void testRecycleStopItem() { StopActivityItem emptyItem = StopActivityItem.obtain(0); diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java index 7e9933c8d9dff..02e75dd76a077 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java +++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java @@ -18,6 +18,7 @@ package android.app.servertransaction; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; +import android.app.ActivityOptions; import android.app.ProfilerInfo; import android.app.ResultInfo; import android.content.Intent; @@ -104,6 +105,7 @@ class TestUtils { private PersistableBundle mPersistentState; private List mPendingResults; private List mPendingNewIntents; + private ActivityOptions mActivityOptions; private boolean mIsForward; private ProfilerInfo mProfilerInfo; private IBinder mAssistToken; @@ -174,6 +176,11 @@ class TestUtils { return this; } + LaunchActivityItemBuilder setActivityOptions(ActivityOptions activityOptions) { + mActivityOptions = activityOptions; + return this; + } + LaunchActivityItemBuilder setIsForward(boolean isForward) { mIsForward = isForward; return this; @@ -198,8 +205,8 @@ class TestUtils { return LaunchActivityItem.obtain(mIntent, mIdent, mInfo, mCurConfig, mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mProcState, mState, mPersistentState, mPendingResults, mPendingNewIntents, - mIsForward, mProfilerInfo, mAssistToken, null /* activityClientController */, - mFixedRotationAdjustments); + mActivityOptions, mIsForward, mProfilerInfo, mAssistToken, + null /* activityClientController */, mFixedRotationAdjustments); } } } diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index e1c7146908d67..5705dd530c168 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -24,6 +24,7 @@ import static android.app.servertransaction.TestUtils.resultInfoList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import android.app.ActivityOptions; import android.app.ContentProviderHolder; import android.app.IApplicationThread; import android.app.IInstrumentationWatcher; @@ -200,9 +201,10 @@ public class TransactionParcelTests { .setIntent(intent).setIdent(ident).setInfo(activityInfo).setCurConfig(config()) .setOverrideConfig(overrideConfig).setCompatInfo(compat).setReferrer(referrer) .setProcState(procState).setState(bundle).setPersistentState(persistableBundle) - .setPendingResults(resultInfoList()).setPendingNewIntents(referrerIntentList()) - .setIsForward(true).setAssistToken(new Binder()) - .setFixedRotationAdjustments(fixedRotationAdjustments).build(); + .setPendingResults(resultInfoList()).setActivityOptions(ActivityOptions.makeBasic()) + .setPendingNewIntents(referrerIntentList()).setIsForward(true) + .setAssistToken(new Binder()).setFixedRotationAdjustments(fixedRotationAdjustments) + .build(); writeAndPrepareForReading(item); @@ -273,7 +275,7 @@ public class TransactionParcelTests { @Test public void testStart() { // Write to parcel - StartActivityItem item = StartActivityItem.obtain(); + StartActivityItem item = StartActivityItem.obtain(ActivityOptions.makeBasic()); writeAndPrepareForReading(item); // Read from parcel and assert diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java index a74f580b65e69..d2b20b4298d9f 100644 --- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java +++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java @@ -242,7 +242,7 @@ public class ActivityThreadClientTest { } private void startActivity(ActivityClientRecord r) { - mThread.handleStartActivity(r, null /* pendingActions */); + mThread.handleStartActivity(r, null /* pendingActions */, null /* activityOptions */); } private void resumeActivity(ActivityClientRecord r) { @@ -295,8 +295,9 @@ public class ActivityThreadClientTest { 0 /* ident */, info, new Configuration(), CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null /* referrer */, null /* voiceInteractor */, null /* state */, null /* persistentState */, - null /* pendingResults */, null /* pendingNewIntents */, true /* isForward */, - null /* profilerInfo */, mThread /* client */, null /* asssitToken */, + null /* pendingResults */, null /* pendingNewIntents */, + null /* activityOptions */, true /* isForward */, null /* profilerInfo */, + mThread /* client */, null /* asssitToken */, null /* fixedRotationAdjustments */); } diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java index a61e08aa1c814..e333f3814a615 100644 --- a/services/core/java/com/android/server/wm/ActivityClientController.java +++ b/services/core/java/com/android/server/wm/ActivityClientController.java @@ -42,7 +42,6 @@ import static com.android.server.wm.Task.ActivityState.DESTROYING; import android.annotation.NonNull; import android.app.Activity; import android.app.ActivityManager; -import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.app.IActivityClientController; import android.app.PictureInPictureParams; @@ -556,23 +555,6 @@ class ActivityClientController extends IActivityClientController.Stub { } } - @Override - public Bundle getActivityOptions(IBinder token) { - final long origId = Binder.clearCallingIdentity(); - try { - synchronized (mGlobalLock) { - final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); - if (r == null) { - return null; - } - final ActivityOptions activityOptions = r.takeOptionsLocked(true /* fromClient */); - return activityOptions != null ? activityOptions.toBundle() : null; - } - } finally { - Binder.restoreCallingIdentity(origId); - } - } - @Override public void setRequestedOrientation(IBinder token, int requestedOrientation) { final long origId = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index ef845c843c5f7..16538962d910c 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -284,6 +284,7 @@ import android.view.DisplayInfo; import android.view.IAppTransitionAnimationSpecsFuture; import android.view.IApplicationToken; import android.view.InputApplicationHandle; +import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationDefinition; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; @@ -462,7 +463,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A HashSet> pendingResults; // all pending intents for this act ArrayList newIntents; // any pending new intents for single-top mode Intent mLastNewIntent; // the last new intent we delivered to client - ActivityOptions pendingOptions; // most recently given options + /** The most recently given options. */ + private ActivityOptions mPendingOptions; + /** Non-null if {@link #mPendingOptions} specifies the remote animation. */ + private RemoteAnimationAdapter mPendingRemoteAnimation; ActivityOptions returningOptions; // options that are coming back via convertToTranslucent AppTimeTracker appTimeTracker; // set if we are tracking the time in this app/task/activity ActivityServiceConnectionsHolder mServiceConnectionsHolder; // Service connections. @@ -882,8 +886,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } } - if (pendingOptions != null) { - pw.print(prefix); pw.print("pendingOptions="); pw.println(pendingOptions); + if (mPendingOptions != null) { + pw.print(prefix); pw.print("pendingOptions="); pw.println(mPendingOptions); + } + if (mPendingRemoteAnimation != null) { + pw.print(prefix); + pw.print("pendingRemoteAnimationCallingPid="); + pw.println(mPendingRemoteAnimation.getCallingPid()); } if (appTimeTracker != null) { appTimeTracker.dumpWithHeader(pw, prefix, false); @@ -1633,8 +1642,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A lockTaskLaunchMode = getLockTaskLaunchMode(aInfo, options); if (options != null) { - pendingOptions = options; - final PendingIntent usageReport = pendingOptions.getUsageTimeReport(); + setOptions(options); + final PendingIntent usageReport = options.getUsageTimeReport(); if (usageReport != null) { appTimeTracker = new AppTimeTracker(usageReport); } @@ -2206,7 +2215,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (task != null && !finishing) { task = null; } - clearOptionsLocked(); + abortAndClearOptionsAnimation(); } } @@ -2993,7 +3002,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } finishing = true; if (stopped) { - clearOptionsLocked(); + abortAndClearOptionsAnimation(); } mAtmService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, this); } @@ -3861,33 +3870,47 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A void updateOptionsLocked(ActivityOptions options) { if (options != null) { if (DEBUG_TRANSITION) Slog.i(TAG, "Update options for " + this); - if (pendingOptions != null) { - pendingOptions.abort(); + if (mPendingOptions != null) { + mPendingOptions.abort(); } - pendingOptions = options; + setOptions(options); } } - void applyOptionsLocked() { - if (pendingOptions != null - && pendingOptions.getAnimationType() != ANIM_SCENE_TRANSITION) { - if (DEBUG_TRANSITION) Slog.i(TAG, "Applying options for " + this); - applyOptionsLocked(pendingOptions, intent); - if (task == null) { - clearOptionsLocked(false /* withAbort */); - } else { - // This will clear the options for all the ActivityRecords for this Task. - task.forAllActivities((r) -> { - r.clearOptionsLocked(false /* withAbort */); - }); + private void setOptions(@NonNull ActivityOptions options) { + mPendingOptions = options; + if (options.getAnimationType() == ANIM_REMOTE_ANIMATION) { + mPendingRemoteAnimation = options.getRemoteAnimationAdapter(); + } + } + + void applyOptionsAnimation() { + if (DEBUG_TRANSITION) Slog.i(TAG, "Applying options for " + this); + if (mPendingRemoteAnimation != null) { + mDisplayContent.mAppTransition.overridePendingAppTransitionRemote( + mPendingRemoteAnimation); + } else { + if (mPendingOptions == null + || mPendingOptions.getAnimationType() == ANIM_SCENE_TRANSITION) { + // Scene transition will run on the client side. + return; } + applyOptionsAnimation(mPendingOptions, intent); + } + if (task == null) { + clearOptionsAnimation(); + } else { + // This will clear the options for all the ActivityRecords for this Task. + task.forAllActivities((r) -> { + r.clearOptionsAnimation(); + }); } } /** * Apply override app transition base on options & animation type. */ - void applyOptionsLocked(ActivityOptions pendingOptions, Intent intent) { + private void applyOptionsAnimation(ActivityOptions pendingOptions, Intent intent) { final int animationType = pendingOptions.getAnimationType(); final DisplayContent displayContent = getDisplayContent(); switch (animationType) { @@ -3969,10 +3992,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A displayContent.mAppTransition .overridePendingAppTransitionStartCrossProfileApps(); break; - case ANIM_REMOTE_ANIMATION: - displayContent.mAppTransition.overridePendingAppTransitionRemote( - pendingOptions.getRemoteAnimationAdapter()); - break; case ANIM_NONE: case ANIM_UNDEFINED: break; @@ -4033,35 +4052,32 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } - void clearOptionsLocked() { - clearOptionsLocked(true /* withAbort */); - } - - void clearOptionsLocked(boolean withAbort) { - if (withAbort && pendingOptions != null) { - pendingOptions.abort(); + void abortAndClearOptionsAnimation() { + if (mPendingOptions != null) { + mPendingOptions.abort(); } - pendingOptions = null; + clearOptionsAnimation(); } - ActivityOptions takeOptionsLocked(boolean fromClient) { + void clearOptionsAnimation() { + mPendingOptions = null; + mPendingRemoteAnimation = null; + } + + ActivityOptions getOptions() { + return mPendingOptions; + } + + ActivityOptions takeOptions() { if (DEBUG_TRANSITION) Slog.i(TAG, "Taking options for " + this + " callers=" + Debug.getCallers(6)); - ActivityOptions opts = pendingOptions; - - // If we are trying to take activity options from the client, do not null it out if it's a - // remote animation as the client doesn't need it ever. This is a workaround when client is - // faster to take the options than we are to resume the next activity. - // TODO (b/132432864): Fix the root cause of these transition preparing/applying options - // timing somehow - if (!fromClient || opts == null || opts.getRemoteAnimationAdapter() == null) { - pendingOptions = null; - } + final ActivityOptions opts = mPendingOptions; + mPendingOptions = null; return opts; } boolean allowMoveToFront() { - return pendingOptions == null || !pendingOptions.getAvoidMoveToFront(); + return mPendingOptions == null || !mPendingOptions.getAvoidMoveToFront(); } void removeUriPermissionsLocked() { @@ -4883,7 +4899,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A try { mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, - StartActivityItem.obtain()); + StartActivityItem.obtain(takeOptions())); } catch (Exception e) { Slog.w(TAG, "Exception thrown sending start: " + intent.getComponent(), e); } @@ -5204,7 +5220,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A notifyAppStopped(); if (finishing) { - clearOptionsLocked(); + abortAndClearOptionsAnimation(); } else { if (deferRelaunchUntilPaused) { destroyImmediately("stop-config"); @@ -5838,8 +5854,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // We don't show starting window for overlay activities. return; } - if (pendingOptions != null - && pendingOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) { + if (mPendingOptions != null + && mPendingOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) { // Don't show starting window when using shared element transition. return; } diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index f9e85cdd8d8af..2dd8c597450e2 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -528,7 +528,7 @@ public class ActivityStartController { "pendingActivityLaunch"); try { starter.startResolvedActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags, - resume, pal.r.pendingOptions, null, pal.intentGrants); + resume, pal.r.getOptions(), null, pal.intentGrants); } catch (Exception e) { Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e); pal.sendErrorResult(e.getMessage()); diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index e30cd05c79a08..5289f8604f361 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1258,7 +1258,7 @@ class ActivityStarter { } // We pretend to the caller that it was really started to make it backward compatible, but // they will just get a cancel result. - ActivityOptions.abort(r.pendingOptions); + ActivityOptions.abort(r.getOptions()); return true; } diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 16f415fd97811..9d291b12c2c93 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -868,8 +868,8 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { mergedConfiguration.getOverrideConfiguration(), r.compat, r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(), results, newIntents, - dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(), - r.assistToken, activityClientController, + r.takeOptions(), dc.isNextTransitionForward(), + proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController, r.createFixedRotationAdjustmentsIfNeeded())); // Set desired final state. @@ -2566,9 +2566,10 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { try { mService.moveTaskToFrontLocked(null /* appThread */, null /* callingPackage */, task.mTaskId, 0, options); - // Apply options to prevent pendingOptions be taken by client to make sure - // the override pending app transition will be applied immediately. - targetActivity.applyOptionsLocked(); + // Apply options to prevent pendingOptions be taken when scheduling activity + // lifecycle transaction to make sure the override pending app transition will + // be applied immediately. + targetActivity.applyOptionsAnimation(); } finally { mActivityMetricsLogger.notifyActivityLaunched(launchingState, START_TASK_TO_FRONT, targetActivity, activityOptions); diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java index 17cb8905f2600..fc347bc609d18 100644 --- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java +++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java @@ -267,8 +267,9 @@ class ResetTargetTaskHelper { private boolean takeOption(ActivityRecord p, boolean noOptions) { mCanMoveOptions = false; if (noOptions && mTopOptions == null) { - mTopOptions = p.takeOptionsLocked(false /* fromClient */); + mTopOptions = p.getOptions(); if (mTopOptions != null) { + p.clearOptionsAnimation(); noOptions = false; } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 2290c23be5137..81cbd61d62d73 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -1926,8 +1926,9 @@ class Task extends WindowContainer { if (r == boundaryActivity) return true; if (!r.finishing) { - final ActivityOptions opts = r.takeOptionsLocked(false /* fromClient */); + final ActivityOptions opts = r.getOptions(); if (opts != null) { + r.clearOptionsAnimation(); // TODO: Why is this updating the boundary activity vs. the current activity??? boundaryActivity.updateOptionsLocked(opts); } @@ -6247,9 +6248,9 @@ class Task extends WindowContainer { } if (anim) { - next.applyOptionsLocked(); + next.applyOptionsAnimation(); } else { - next.clearOptionsLocked(); + next.abortAndClearOptionsAnimation(); } mTaskSupervisor.mNoAnimActivities.clear(); @@ -6356,7 +6357,7 @@ class Task extends WindowContainer { mAtmService.getAppWarningsLocked().onResumeActivity(next); next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState); - next.clearOptionsLocked(); + next.abortAndClearOptionsAnimation(); transaction.setLifecycleStateRequest( ResumeActivityItem.obtain(next.app.getReportedProcState(), dc.isNextTransitionForward())); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index b50e50b89683b..39e3bffd33499 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -254,26 +254,26 @@ public class ActivityRecordTests extends WindowTestsBase { // Set and apply options for ActivityRecord. Pending options should be cleared activity.updateOptionsLocked(activityOptions); - activity.applyOptionsLocked(); - assertNull(activity.pendingOptions); + activity.applyOptionsAnimation(); + assertNull(activity.getOptions()); // Set options for two ActivityRecords in same Task. Apply one ActivityRecord options. // Pending options should be cleared for both ActivityRecords ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(activity.getTask()).build(); activity2.updateOptionsLocked(activityOptions); activity.updateOptionsLocked(activityOptions); - activity.applyOptionsLocked(); - assertNull(activity.pendingOptions); - assertNull(activity2.pendingOptions); + activity.applyOptionsAnimation(); + assertNull(activity.getOptions()); + assertNull(activity2.getOptions()); // Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options. // Pending options should be cleared for only ActivityRecord that was applied activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build(); activity2.updateOptionsLocked(activityOptions); activity.updateOptionsLocked(activityOptions); - activity.applyOptionsLocked(); - assertNull(activity.pendingOptions); - assertNotNull(activity2.pendingOptions); + activity.applyOptionsAnimation(); + assertNull(activity.getOptions()); + assertNotNull(activity2.getOptions()); } @Test @@ -653,21 +653,21 @@ public class ActivityRecordTests extends WindowTestsBase { public void onAnimationStart(RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, IRemoteAnimationFinishedCallback finishedCallback) { - } @Override public void onAnimationCancelled() { - } }, 0, 0)); activity.updateOptionsLocked(opts); - assertNotNull(activity.takeOptionsLocked(true /* fromClient */)); - assertNotNull(activity.pendingOptions); + assertNotNull(activity.takeOptions()); + assertNull(activity.getOptions()); - activity.updateOptionsLocked(ActivityOptions.makeBasic()); - assertNotNull(activity.takeOptionsLocked(false /* fromClient */)); - assertNull(activity.pendingOptions); + final AppTransition appTransition = activity.mDisplayContent.mAppTransition; + spyOn(appTransition); + activity.applyOptionsAnimation(); + + verify(appTransition).overridePendingAppTransitionRemote(any()); } @Test