diff options
-rw-r--r-- | apps/CtsVerifier/AndroidManifest.xml | 2 | ||||
-rw-r--r-- | tests/tests/security/AndroidManifest.xml | 3 | ||||
-rw-r--r-- | tests/tests/security/src/android/security/cts/ActivityManagerTest.java | 178 |
3 files changed, 178 insertions, 5 deletions
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml index 307e19907d4..efa1de71ecd 100644 --- a/apps/CtsVerifier/AndroidManifest.xml +++ b/apps/CtsVerifier/AndroidManifest.xml @@ -4208,6 +4208,7 @@ android:value="android.hardware.type.automotive:android.hardware.ram.low" /> <meta-data android:name="display_mode" android:value="multi_display_mode" /> + <meta-data android:name="CddTest" android:value="3.8.2/C-1-2,C-1-3" /> </activity> <activity android:name=".deskclock.DeskClockTestsActivity" @@ -5233,6 +5234,7 @@ android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch:android.hardware.type.automotive" /> <meta-data android:name="display_mode" android:value="multi_display_mode" /> + <meta-data android:name="CddTest" android:value="3.8.8/C-1-2"/> </activity> <activity android:name=".tv.MockTvInputSetupActivity" diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml index 186c5e2ab7b..4ddeca0e23c 100644 --- a/tests/tests/security/AndroidManifest.xml +++ b/tests/tests/security/AndroidManifest.xml @@ -201,6 +201,9 @@ </intent-filter> </activity> + <activity android:name="android.security.cts.ActivityManagerTest$ActivityOptionsActivity" /> + <activity android:name="android.security.cts.ActivityManagerTest$BaseActivity" /> + </application> <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" diff --git a/tests/tests/security/src/android/security/cts/ActivityManagerTest.java b/tests/tests/security/src/android/security/cts/ActivityManagerTest.java index f16b8fb2111..a27a0b940cd 100644 --- a/tests/tests/security/src/android/security/cts/ActivityManagerTest.java +++ b/tests/tests/security/src/android/security/cts/ActivityManagerTest.java @@ -15,24 +15,43 @@ */ package android.security.cts; +import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION; +import static android.view.Window.FEATURE_ACTIVITY_TRANSITIONS; + import static org.junit.Assert.*; +import android.app.Activity; import android.app.ActivityManager; -import android.app.ApplicationExitInfo; +import android.app.ActivityOptions; +import android.app.Application; import android.content.Context; +import android.content.Intent; +import android.os.Bundle; import android.os.IBinder; +import android.os.RemoteException; import android.platform.test.annotations.AsbSecurityTest; import android.util.Log; -import androidx.test.runner.AndroidJUnit4; +import android.view.SurfaceControl; +import android.window.IRemoteTransition; +import android.window.IRemoteTransitionFinishedCallback; +import android.window.RemoteTransition; +import android.window.TransitionInfo; import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.compatibility.common.util.SystemUtil; import com.android.sts.common.util.StsExtraBusinessLogicTestCase; -import junit.framework.TestCase; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.Callable; -import org.junit.runner.RunWith; -import org.junit.Test; @RunWith(AndroidJUnit4.class) public class ActivityManagerTest extends StsExtraBusinessLogicTestCase { @@ -111,6 +130,51 @@ public class ActivityManagerTest extends StsExtraBusinessLogicTestCase { assertTrue(Math.abs((double) mockPackagescores / totalLoops - 0.5d) < tolerance); } + @AsbSecurityTest(cveBugId = 237290578) + @Test + public void testActivityManager_stripTransitionFromActivityOptions() throws Exception { + Context targetContext = getInstrumentation().getTargetContext(); + + // Need to start a base activity since this requires shared element transition. + final Intent baseIntent = new Intent(targetContext, BaseActivity.class); + baseIntent.setFlags(FLAG_ACTIVITY_NO_USER_ACTION | FLAG_ACTIVITY_NEW_TASK); + final BaseActivity baseActivity = (BaseActivity) SystemUtil.callWithShellPermissionIdentity( + () -> getInstrumentation().startActivitySync(baseIntent)); + + RemoteTransition someRemote = new RemoteTransition(new IRemoteTransition.Stub() { + @Override + public void startAnimation(IBinder token, TransitionInfo info, + SurfaceControl.Transaction t, + IRemoteTransitionFinishedCallback finishCallback) throws RemoteException { + t.apply(); + finishCallback.onTransitionFinished(null /* wct */, null /* sct */); + } + + @Override + public void mergeAnimation(IBinder token, TransitionInfo info, + SurfaceControl.Transaction t, IBinder mergeTarget, + IRemoteTransitionFinishedCallback finishCallback) throws RemoteException { + } + }); + ActivityOptions opts = ActivityOptions.makeRemoteTransition(someRemote); + assertTrue(waitUntil(() -> baseActivity.mResumed)); + ActivityOptions sceneOpts = baseActivity.mSceneOpts; + assertEquals(ANIM_SCENE_TRANSITION, sceneOpts.getAnimationType()); + + // Prepare the intent + final Intent intent = new Intent(targetContext, ActivityOptionsActivity.class); + intent.setFlags(FLAG_ACTIVITY_NO_USER_ACTION | FLAG_ACTIVITY_NEW_TASK); + final Bundle optionsBundle = opts.toBundle(); + optionsBundle.putAll(sceneOpts.toBundle()); + final ActivityOptionsActivity activity = + (ActivityOptionsActivity) SystemUtil.callWithShellPermissionIdentity( + () -> getInstrumentation().startActivitySync(intent, optionsBundle)); + assertTrue(waitUntil(() -> activity.mResumed)); + + assertTrue(activity.mPreCreate || activity.mPreStart); + assertNull(activity.mReceivedTransition); + } + /** * Run ActivityManager.getHistoricalProcessExitReasons once, return the time spent on it. */ @@ -122,4 +186,108 @@ public class ActivityManagerTest extends StsExtraBusinessLogicTestCase { } return System.nanoTime() - start; } + + private boolean waitUntil(Callable<Boolean> test) throws Exception { + long timeoutMs = 2000; + final long timeout = System.currentTimeMillis() + timeoutMs; + while (!test.call()) { + final long waitMs = timeout - System.currentTimeMillis(); + if (waitMs <= 0) break; + try { + wait(timeoutMs); + } catch (InterruptedException e) { + // retry + } + } + return test.call(); + } + + public static class BaseActivity extends Activity { + public boolean mResumed = false; + public ActivityOptions mSceneOpts = null; + + @Override + public void onCreate(Bundle i) { + super.onCreate(i); + getWindow().requestFeature(FEATURE_ACTIVITY_TRANSITIONS); + mSceneOpts = ActivityOptions.makeSceneTransitionAnimation(this); + } + + @Override + public void onResume() { + super.onResume(); + mResumed = true; + } + } + + public static class ActivityOptionsActivity extends Activity { + public RemoteTransition mReceivedTransition = null; + public boolean mPreCreate = false; + public boolean mPreStart = false; + public boolean mResumed = false; + + public ActivityOptionsActivity() { + registerActivityLifecycleCallbacks(new Callbacks()); + } + + private class Callbacks implements Application.ActivityLifecycleCallbacks { + private void accessOptions(Activity activity) { + try { + Field mPendingOptions = Activity.class.getDeclaredField("mPendingOptions"); + mPendingOptions.setAccessible(true); + ActivityOptions options = (ActivityOptions) mPendingOptions.get(activity); + if (options != null) { + mReceivedTransition = options.getRemoteTransition(); + } + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + @Override + public void onActivityPreCreated(Activity activity, Bundle i) { + mPreCreate = true; + if (mReceivedTransition == null) { + accessOptions(activity); + } + } + + @Override + public void onActivityPreStarted(Activity activity) { + mPreStart = true; + if (mReceivedTransition == null) { + accessOptions(activity); + } + } + + @Override + public void onActivityCreated(Activity activity, Bundle savedInstanceState) { + } + + @Override + public void onActivityStarted(Activity activity) { + } + + @Override + public void onActivityResumed(Activity activity) { + mResumed = true; + } + + @Override + public void onActivityPaused(Activity activity) { + } + + @Override + public void onActivityStopped(Activity activity) { + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle outState) { + } + + @Override + public void onActivityDestroyed(Activity activity) { + } + } + } } |