Loading core/java/android/app/ActivityThread.java +144 −145 Original line number Diff line number Diff line Loading @@ -3736,12 +3736,25 @@ public final class ActivityThread extends ClientTransactionHandler { //Slog.i(TAG, "Running services: " + mServices); } ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest, /** * Resume the activity. * @param token Target activity token. * @param finalStateRequest Flag indicating if this is part of final state resolution for a * transaction. * @param reason Reason for performing the action. * * @return The {@link ActivityClientRecord} that was resumed, {@code null} otherwise. */ @VisibleForTesting public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest, String reason) { ActivityClientRecord r = mActivities.get(token); if (localLOGV) Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished); if (r != null && !r.activity.mFinished) { final ActivityClientRecord r = mActivities.get(token); if (localLOGV) { Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished); } if (r == null || r.activity.mFinished) { return null; } if (r.getLifecycleState() == ON_RESUME) { if (!finalStateRequest) { final RuntimeException e = new IllegalStateException( Loading Loading @@ -3779,11 +3792,8 @@ public final class ActivityThread extends ClientTransactionHandler { r.setState(ON_RESUME); } catch (Exception e) { if (!mInstrumentation.onException(r.activity, e)) { throw new RuntimeException( "Unable to resume activity " + r.intent.getComponent().toShortString() + ": " + e.toString(), e); } throw new RuntimeException("Unable to resume activity " + r.intent.getComponent().toShortString() + ": " + e.toString(), e); } } return r; Loading Loading @@ -3816,17 +3826,20 @@ public final class ActivityThread extends ClientTransactionHandler { // TODO Push resumeArgs into the activity for consideration final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); if (r == null) { // We didn't actually resume the activity, so skipping any follow-up actions. return; } if (r != null) { final Activity a = r.activity; if (localLOGV) Slog.v( TAG, "Resume " + r + " started activity: " + a.mStartedActivity + ", hideForNow: " + r.hideForNow + ", finished: " + a.mFinished); if (localLOGV) { Slog.v(TAG, "Resume " + r + " started activity: " + a.mStartedActivity + ", hideForNow: " + r.hideForNow + ", finished: " + a.mFinished); } final int forwardBit = isForward ? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0; final int forwardBit = isForward ? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0; // If the window hasn't yet been added to the window manager, // and this guy didn't finish itself or start another activity, Loading Loading @@ -3878,8 +3891,7 @@ public final class ActivityThread extends ClientTransactionHandler { // we started another activity, then don't yet make the // window visible. } else if (!willBeVisible) { if (localLOGV) Slog.v( TAG, "Launch " + r + " mStartedActivity set"); if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set"); r.hideForNow = true; } Loading @@ -3888,16 +3900,16 @@ public final class ActivityThread extends ClientTransactionHandler { // The window is now visible if it has been added, we are not // simply finishing, and we are not starting another activity. if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) { if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) { if (r.newConfig != null) { performConfigurationChangedForActivity(r, r.newConfig); if (DEBUG_CONFIGURATION) Slog.v(TAG, "Resuming activity " + r.activityInfo.name + " with newConfig " + r.activity.mCurrentConfig); if (DEBUG_CONFIGURATION) { Slog.v(TAG, "Resuming activity " + r.activityInfo.name + " with newConfig " + r.activity.mCurrentConfig); } r.newConfig = null; } if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward); if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward); WindowManager.LayoutParams l = r.window.getAttributes(); if ((l.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) Loading @@ -3921,21 +3933,8 @@ public final class ActivityThread extends ClientTransactionHandler { r.nextIdle = mNewActivities; mNewActivities = r; if (localLOGV) { Slog.v(TAG, "Scheduling idle handler for " + r); } if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r); Looper.myQueue().addIdleHandler(new Idler()); } else { // If an exception was thrown when trying to resume, then // just end this activity. try { ActivityManager.getService() .finishActivity(token, Activity.RESULT_CANCELED, null, Activity.DONT_FINISH_TASK_WITH_ACTIVITY); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } } @Override Loading core/java/android/app/ClientTransactionHandler.java +3 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.content.res.Configuration; import android.os.IBinder; import android.util.MergedConfiguration; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.ReferrerIntent; import java.io.PrintWriter; Loading @@ -48,7 +49,8 @@ public abstract class ClientTransactionHandler { * Execute transaction immediately without scheduling it. This is used for local requests, so * it will also recycle the transaction. */ void executeTransaction(ClientTransaction transaction) { @VisibleForTesting public void executeTransaction(ClientTransaction transaction) { transaction.preExecute(this); getTransactionExecutor().execute(transaction); transaction.recycle(); Loading core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +18 −0 Original line number Diff line number Diff line Loading @@ -16,7 +16,10 @@ package android.app.activity; import static org.junit.Assert.assertNull; import android.app.Activity; import android.app.ActivityThread; import android.app.IApplicationThread; import android.app.servertransaction.ActivityRelaunchItem; import android.app.servertransaction.ClientTransaction; Loading Loading @@ -76,6 +79,21 @@ public class ActivityThreadTest { InstrumentationRegistry.getInstrumentation().waitForIdleSync(); } /** Verify that repeated resume requests to activity will be ignored. */ @Test public void testRepeatedResume() throws Exception { final Activity activity = mActivityTestRule.launchActivity(new Intent()); final ActivityThread activityThread = activity.getActivityThread(); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { activityThread.executeTransaction(newResumeTransaction(activity)); assertNull(activityThread.performResumeActivity(activity.getActivityToken(), true /* finalStateRequest */, "test")); assertNull(activityThread.performResumeActivity(activity.getActivityToken(), false /* finalStateRequest */, "test")); }); } private static ClientTransaction newRelaunchResumeTransaction(Activity activity) { final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null, null, 0, new MergedConfiguration(), false /* preserveWindow */); Loading Loading
core/java/android/app/ActivityThread.java +144 −145 Original line number Diff line number Diff line Loading @@ -3736,12 +3736,25 @@ public final class ActivityThread extends ClientTransactionHandler { //Slog.i(TAG, "Running services: " + mServices); } ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest, /** * Resume the activity. * @param token Target activity token. * @param finalStateRequest Flag indicating if this is part of final state resolution for a * transaction. * @param reason Reason for performing the action. * * @return The {@link ActivityClientRecord} that was resumed, {@code null} otherwise. */ @VisibleForTesting public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest, String reason) { ActivityClientRecord r = mActivities.get(token); if (localLOGV) Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished); if (r != null && !r.activity.mFinished) { final ActivityClientRecord r = mActivities.get(token); if (localLOGV) { Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished); } if (r == null || r.activity.mFinished) { return null; } if (r.getLifecycleState() == ON_RESUME) { if (!finalStateRequest) { final RuntimeException e = new IllegalStateException( Loading Loading @@ -3779,11 +3792,8 @@ public final class ActivityThread extends ClientTransactionHandler { r.setState(ON_RESUME); } catch (Exception e) { if (!mInstrumentation.onException(r.activity, e)) { throw new RuntimeException( "Unable to resume activity " + r.intent.getComponent().toShortString() + ": " + e.toString(), e); } throw new RuntimeException("Unable to resume activity " + r.intent.getComponent().toShortString() + ": " + e.toString(), e); } } return r; Loading Loading @@ -3816,17 +3826,20 @@ public final class ActivityThread extends ClientTransactionHandler { // TODO Push resumeArgs into the activity for consideration final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); if (r == null) { // We didn't actually resume the activity, so skipping any follow-up actions. return; } if (r != null) { final Activity a = r.activity; if (localLOGV) Slog.v( TAG, "Resume " + r + " started activity: " + a.mStartedActivity + ", hideForNow: " + r.hideForNow + ", finished: " + a.mFinished); if (localLOGV) { Slog.v(TAG, "Resume " + r + " started activity: " + a.mStartedActivity + ", hideForNow: " + r.hideForNow + ", finished: " + a.mFinished); } final int forwardBit = isForward ? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0; final int forwardBit = isForward ? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0; // If the window hasn't yet been added to the window manager, // and this guy didn't finish itself or start another activity, Loading Loading @@ -3878,8 +3891,7 @@ public final class ActivityThread extends ClientTransactionHandler { // we started another activity, then don't yet make the // window visible. } else if (!willBeVisible) { if (localLOGV) Slog.v( TAG, "Launch " + r + " mStartedActivity set"); if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set"); r.hideForNow = true; } Loading @@ -3888,16 +3900,16 @@ public final class ActivityThread extends ClientTransactionHandler { // The window is now visible if it has been added, we are not // simply finishing, and we are not starting another activity. if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) { if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) { if (r.newConfig != null) { performConfigurationChangedForActivity(r, r.newConfig); if (DEBUG_CONFIGURATION) Slog.v(TAG, "Resuming activity " + r.activityInfo.name + " with newConfig " + r.activity.mCurrentConfig); if (DEBUG_CONFIGURATION) { Slog.v(TAG, "Resuming activity " + r.activityInfo.name + " with newConfig " + r.activity.mCurrentConfig); } r.newConfig = null; } if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward); if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward); WindowManager.LayoutParams l = r.window.getAttributes(); if ((l.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) Loading @@ -3921,21 +3933,8 @@ public final class ActivityThread extends ClientTransactionHandler { r.nextIdle = mNewActivities; mNewActivities = r; if (localLOGV) { Slog.v(TAG, "Scheduling idle handler for " + r); } if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r); Looper.myQueue().addIdleHandler(new Idler()); } else { // If an exception was thrown when trying to resume, then // just end this activity. try { ActivityManager.getService() .finishActivity(token, Activity.RESULT_CANCELED, null, Activity.DONT_FINISH_TASK_WITH_ACTIVITY); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } } @Override Loading
core/java/android/app/ClientTransactionHandler.java +3 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.content.res.Configuration; import android.os.IBinder; import android.util.MergedConfiguration; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.ReferrerIntent; import java.io.PrintWriter; Loading @@ -48,7 +49,8 @@ public abstract class ClientTransactionHandler { * Execute transaction immediately without scheduling it. This is used for local requests, so * it will also recycle the transaction. */ void executeTransaction(ClientTransaction transaction) { @VisibleForTesting public void executeTransaction(ClientTransaction transaction) { transaction.preExecute(this); getTransactionExecutor().execute(transaction); transaction.recycle(); Loading
core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +18 −0 Original line number Diff line number Diff line Loading @@ -16,7 +16,10 @@ package android.app.activity; import static org.junit.Assert.assertNull; import android.app.Activity; import android.app.ActivityThread; import android.app.IApplicationThread; import android.app.servertransaction.ActivityRelaunchItem; import android.app.servertransaction.ClientTransaction; Loading Loading @@ -76,6 +79,21 @@ public class ActivityThreadTest { InstrumentationRegistry.getInstrumentation().waitForIdleSync(); } /** Verify that repeated resume requests to activity will be ignored. */ @Test public void testRepeatedResume() throws Exception { final Activity activity = mActivityTestRule.launchActivity(new Intent()); final ActivityThread activityThread = activity.getActivityThread(); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { activityThread.executeTransaction(newResumeTransaction(activity)); assertNull(activityThread.performResumeActivity(activity.getActivityToken(), true /* finalStateRequest */, "test")); assertNull(activityThread.performResumeActivity(activity.getActivityToken(), false /* finalStateRequest */, "test")); }); } private static ClientTransaction newRelaunchResumeTransaction(Activity activity) { final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null, null, 0, new MergedConfiguration(), false /* preserveWindow */); Loading