Merge "Don't throw exception for duplicate resume" into pi-dev

am: ee83dd2cd0

Change-Id: I91a3009cd6e81632f203659c21c261b00e417e15
This commit is contained in:
Andrii Kulian
2018-03-13 01:21:25 +00:00
committed by android-build-merger
7 changed files with 136 additions and 11 deletions

View File

@@ -124,6 +124,7 @@ import android.widget.Toast;
import android.widget.Toolbar;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ToolbarActionBar;
import com.android.internal.app.WindowDecorActionBar;
@@ -7110,6 +7111,12 @@ public class Activity extends ContextThemeWrapper
return mParent != null ? mParent.getActivityToken() : mToken;
}
/** @hide */
@VisibleForTesting
public final ActivityThread getActivityThread() {
return mMainThread;
}
final void performCreate(Bundle icicle) {
performCreate(icicle, null);
}

View File

@@ -3722,16 +3722,27 @@ public final class ActivityThread extends ClientTransactionHandler {
//Slog.i(TAG, "Running services: " + mServices);
}
ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide, String reason) {
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) {
if (r.getLifecycleState() == ON_RESUME) {
throw new IllegalStateException(
"Trying to resume activity which is already resumed");
if (!finalStateRequest) {
final RuntimeException e = new IllegalStateException(
"Trying to resume activity which is already resumed");
Slog.e(TAG, e.getMessage(), e);
Slog.e(TAG, r.getStateString());
// TODO(lifecycler): A double resume request is possible when an activity
// receives two consequent transactions with relaunch requests and "resumed"
// final state requests and the second relaunch is omitted. We still try to
// handle two resume requests for the final state. For cases other than this
// one, we don't expect it to happen.
}
return null;
}
if (clearHide) {
if (finalStateRequest) {
r.hideForNow = false;
r.activity.mStartedActivity = false;
}
@@ -3782,7 +3793,7 @@ public final class ActivityThread extends ClientTransactionHandler {
}
@Override
public void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
@@ -3790,7 +3801,7 @@ public final class ActivityThread extends ClientTransactionHandler {
mSomeActivitiesChanged = true;
// TODO Push resumeArgs into the activity for consideration
final ActivityClientRecord r = performResumeActivity(token, clearHide, reason);
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
if (r != null) {
final Activity a = r.activity;

View File

@@ -67,9 +67,16 @@ public abstract class ClientTransactionHandler {
public abstract void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
int configChanges, PendingTransactionActions pendingActions, String reason);
/** Resume the activity. */
public abstract void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
String reason);
/**
* Resume the activity.
* @param token Target activity token.
* @param finalStateRequest Flag indicating if this call is handling final lifecycle state
* request for a transaction.
* @param isForward Flag indicating if next transition is forward.
* @param reason Reason for performing this operation.
*/
public abstract void handleResumeActivity(IBinder token, boolean finalStateRequest,
boolean isForward, String reason);
/** Stop the activity. */
public abstract void handleStopActivity(IBinder token, boolean show, int configChanges,

View File

@@ -48,7 +48,8 @@ public class ResumeActivityItem extends ActivityLifecycleItem {
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
client.handleResumeActivity(token, true /* clearHide */, mIsForward, "RESUME_ACTIVITY");
client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,
"RESUME_ACTIVITY");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}

View File

@@ -191,7 +191,7 @@ public class TransactionExecutor {
mTransactionHandler.handleStartActivity(r, mPendingActions);
break;
case ON_RESUME:
mTransactionHandler.handleResumeActivity(r.token, false /* clearHide */,
mTransactionHandler.handleResumeActivity(r.token, false /* finalStateRequest */,
r.isForward, "LIFECYCLER_RESUME_ACTIVITY");
break;
case ON_PAUSE:

View File

@@ -1379,6 +1379,10 @@
android:theme="@style/Theme">
</activity>
<activity android:name="android.app.activity.ActivityThreadTest$TestActivity"
android:exported="true">
</activity>
<activity
android:name="android.os.TestVrActivity"
android:enableVrMode="com.android.frameworks.coretests/android.os.TestVrActivity$TestVrListenerService">

View File

@@ -0,0 +1,95 @@
/*
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.activity;
import android.app.Activity;
import android.app.IApplicationThread;
import android.app.servertransaction.ActivityRelaunchItem;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.ClientTransactionItem;
import android.app.servertransaction.ResumeActivityItem;
import android.content.Intent;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.util.MergedConfiguration;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Test for verifying {@link android.app.ActivityThread} class.
*/
@RunWith(AndroidJUnit4.class)
@MediumTest
public class ActivityThreadTest {
private final ActivityTestRule mActivityTestRule =
new ActivityTestRule(TestActivity.class, true /* initialTouchMode */,
false /* launchActivity */);
@Test
public void testDoubleRelaunch() throws Exception {
final Activity activity = mActivityTestRule.launchActivity(new Intent());
final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
appThread.scheduleTransaction(newRelaunchResumeTransaction(activity));
appThread.scheduleTransaction(newRelaunchResumeTransaction(activity));
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@Test
public void testResumeAfterRelaunch() throws Exception {
final Activity activity = mActivityTestRule.launchActivity(new Intent());
final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
appThread.scheduleTransaction(newRelaunchResumeTransaction(activity));
appThread.scheduleTransaction(newResumeTransaction(activity));
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
private static ClientTransaction newRelaunchResumeTransaction(Activity activity) {
final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null,
null, 0, new MergedConfiguration(),
false /* preserveWindow */);
final ResumeActivityItem resumeStateRequest =
ResumeActivityItem.obtain(true /* isForward */);
final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
final ClientTransaction transaction =
ClientTransaction.obtain(appThread, activity.getActivityToken());
transaction.addCallback(callbackItem);
transaction.setLifecycleStateRequest(resumeStateRequest);
return transaction;
}
private static ClientTransaction newResumeTransaction(Activity activity) {
final ResumeActivityItem resumeStateRequest =
ResumeActivityItem.obtain(true /* isForward */);
final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
final ClientTransaction transaction =
ClientTransaction.obtain(appThread, activity.getActivityToken());
transaction.setLifecycleStateRequest(resumeStateRequest);
return transaction;
}
// Test activity
public static class TestActivity extends Activity {
}
}