STS test for Android Security Bug 183794206

Tapjacking test for ResetOptionsActivity in Android Car Settings.

Bug: 183794206
Test: atest
android.security.cts.Bug_183794206#testRunDeviceTestsPassesFull (passes
when overlays not allowed, fails otherwise)

Change-Id: Ie4f2e6ee62a5de6b88cb4d32ee80ecfea6048fc5
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183794206.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183794206.java
new file mode 100644
index 0000000..73cfdb9
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183794206.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 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.security.cts;
+
+import static org.junit.Assume.assumeTrue;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import org.junit.Test;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class Bug_183794206 extends SecurityTestCase {
+    private static final String TEST_PKG = "android.security.cts.BUG_183794206";
+    private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+    private static final String TEST_APP = "BUG-183794206.apk";
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        assumeTrue(
+                "not an Automotive device",
+                getDevice().hasFeature("feature:android.hardware.type.automotive"));
+        uninstallPackage(getDevice(), TEST_PKG);
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 183794206)
+    public void testRunDeviceTestsPassesFull() throws Exception {
+        installPackage(TEST_APP);
+
+        // Grant permission to draw overlays.
+        getDevice().executeShellCommand(
+                "pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW");
+
+        assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testTapjacking"));
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183794206/Android.bp b/hostsidetests/securitybulletin/test-apps/BUG-183794206/Android.bp
new file mode 100644
index 0000000..b022003
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-183794206/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2021 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.
+android_test_helper_app {
+    name: "BUG-183794206",
+    defaults: ["cts_support_defaults"],
+    srcs: ["src/**/*.java"],
+    test_suites: [
+        "cts",
+        "vts10",
+        "sts",
+    ],
+    static_libs: [
+        "androidx.appcompat_appcompat",
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+        "androidx.test.core",
+    ],
+    sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183794206/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/BUG-183794206/AndroidManifest.xml
new file mode 100644
index 0000000..b7e21c7
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-183794206/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.security.cts.BUG_183794206"
+          android:targetSandboxVersion="2">
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+    <application
+        android:label="@string/app_name"
+        android:theme="@style/Theme.AppCompat.Light">
+        <uses-library android:name="android.test.runner" />
+        <service android:name=".OverlayService"
+                 android:enabled="true"
+                 android:exported="false" />
+        <activity
+            android:name=".MainActivity"
+            android:label="ST (Permission)"
+            android:exported="true"
+            android:taskAffinity="android.security.cts.BUG_183794206.MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.security.cts.BUG_183794206" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183794206/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/BUG-183794206/res/layout/activity_main.xml
new file mode 100644
index 0000000..e8bfd4a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-183794206/res/layout/activity_main.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="left"
+    tools:context=".MainActivity" >
+    <LinearLayout
+        android:id="@+id/linearLayout1"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/seekShowTimes"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="53dp"
+        android:orientation="horizontal" >
+        <Button
+            android:id="@+id/btnStart"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Start" />
+    </LinearLayout>
+</RelativeLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183794206/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/BUG-183794206/res/values/strings.xml
new file mode 100644
index 0000000..f4d34b8
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-183794206/res/values/strings.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<resources>
+    <string name="app_name">BUG_183794206</string>
+    <string name="tapjacking_text">BUG_183794206 overlay text</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183794206/src/android/security/cts/BUG_183794206/Constants.java b/hostsidetests/securitybulletin/test-apps/BUG-183794206/src/android/security/cts/BUG_183794206/Constants.java
new file mode 100644
index 0000000..39ceec5
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-183794206/src/android/security/cts/BUG_183794206/Constants.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 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.security.cts.BUG_183794206;
+
+final class Constants {
+
+    public static final String TAG = "BUG-183794206";
+    public static final String TEST_APP_PACKAGE = Constants.class.getPackage().getName();
+    public static final String CAR_SETTINGS_APP_PACKAGE = "com.android.car.settings";
+
+    public static final String TAPJACKED_ACTIVITY_INTENT_CLASS =
+            CAR_SETTINGS_APP_PACKAGE + ".common.CarSettingActivities$ResetOptionsActivity";
+    public static final String ACTION_START_TAPJACKING = TAG + ".start_tapjacking";
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183794206/src/android/security/cts/BUG_183794206/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/BUG-183794206/src/android/security/cts/BUG_183794206/DeviceTest.java
new file mode 100644
index 0000000..6daebec
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-183794206/src/android/security/cts/BUG_183794206/DeviceTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2021 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.security.cts.BUG_183794206;
+
+import static android.security.cts.BUG_183794206.Constants.CAR_SETTINGS_APP_PACKAGE;
+import static android.security.cts.BUG_183794206.Constants.TAG;
+import static android.security.cts.BUG_183794206.Constants.TAPJACKED_ACTIVITY_INTENT_CLASS;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Basic sample for unbundled UiAutomator. */
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+    private static final long WAIT_FOR_UI_TIMEOUT = 10_000;
+
+    private Context mContext;
+    private UiDevice mDevice;
+
+    @Before
+    public void setUp() throws Exception {
+        Log.d(TAG, "startMainActivityFromHomeScreen()");
+
+        mContext = getApplicationContext();
+
+        // If the permission is not granted, the app will not be able to show an overlay dialog.
+        // This is required for the test below.
+        // NOTE: The permission is granted by the HostJUnit4Test implementation and should not fail.
+        assertEquals("Permission SYSTEM_ALERT_WINDOW not granted!",
+                mContext.checkSelfPermission("android.permission.SYSTEM_ALERT_WINDOW"),
+                PackageManager.PERMISSION_GRANTED);
+
+        // Initialize UiDevice instance
+        mDevice = UiDevice.getInstance(getInstrumentation());
+        if (!mDevice.isScreenOn()) {
+            mDevice.wakeUp();
+        }
+        mDevice.pressHome();
+    }
+
+    @Test
+    public void testTapjacking() throws InterruptedException {
+        Log.d(TAG, "Starting tap-jacking test");
+
+        launchTestApp();
+
+        launchTapjackedActivity();
+
+        mContext.sendBroadcast(new Intent(Constants.ACTION_START_TAPJACKING));
+        Log.d(TAG, "Sent intent to start tap-jacking!");
+
+        UiObject2 overlay = waitForView(By.text(mContext.getString(R.string.tapjacking_text)));
+        assertNull("Tap-jacking successful. Overlay was displayed.!", overlay);
+    }
+
+    @After
+    public void tearDown() {
+        mDevice.pressHome();
+    }
+
+    private void launchTestApp() {
+        Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(
+                Constants.TEST_APP_PACKAGE);
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        mContext.startActivity(intent);
+
+        // Wait for the app to appear
+        UiObject2 view = waitForView(By.pkg(Constants.TEST_APP_PACKAGE).depth(0));
+        assertNotNull("test-app did not appear!", view);
+        Log.d(TAG, "test-app appeared");
+    }
+
+    private void launchTapjackedActivity() {
+        Intent intent = new Intent();
+        intent.setComponent(
+                new ComponentName(CAR_SETTINGS_APP_PACKAGE, TAPJACKED_ACTIVITY_INTENT_CLASS));
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(intent);
+
+        UiObject2 activityInstance = waitForView(By.pkg(CAR_SETTINGS_APP_PACKAGE).depth(0));
+        assertNotNull("Activity under-test was not launched or found!", activityInstance);
+        Log.d(TAG, "Started Activity under-test.");
+    }
+
+    private UiObject2 waitForView(BySelector selector) {
+        return mDevice.wait(Until.findObject(selector), WAIT_FOR_UI_TIMEOUT);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183794206/src/android/security/cts/BUG_183794206/MainActivity.java b/hostsidetests/securitybulletin/test-apps/BUG-183794206/src/android/security/cts/BUG_183794206/MainActivity.java
new file mode 100644
index 0000000..4bda943
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-183794206/src/android/security/cts/BUG_183794206/MainActivity.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2021 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.security.cts.BUG_183794206;
+
+import static android.security.cts.BUG_183794206.Constants.TAG;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Button;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+/** Main activity for the test-app. */
+public final class MainActivity extends AppCompatActivity {
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            startTapjacking();
+        }
+    };
+
+    private Button btnStart;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        registerReceiver(mReceiver, new IntentFilter(Constants.ACTION_START_TAPJACKING));
+
+        btnStart = (Button) findViewById(R.id.btnStart);
+        btnStart.setOnClickListener(v -> startTapjacking());
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        unregisterReceiver(mReceiver);
+        stopOverlayService();
+    }
+
+    public void startTapjacking() {
+        Log.d(TAG, "Starting tap-jacking flow.");
+        stopOverlayService();
+
+        startOverlayService();
+        Log.d(TAG, "Started overlay-service.");
+    }
+
+    private void startOverlayService() {
+        startService(new Intent(getApplicationContext(), OverlayService.class));
+    }
+
+    private void stopOverlayService() {
+        stopService(new Intent(getApplicationContext(), OverlayService.class));
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-183794206/src/android/security/cts/BUG_183794206/OverlayService.java b/hostsidetests/securitybulletin/test-apps/BUG-183794206/src/android/security/cts/BUG_183794206/OverlayService.java
new file mode 100644
index 0000000..ad3c428
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-183794206/src/android/security/cts/BUG_183794206/OverlayService.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2021 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.security.cts.BUG_183794206;
+
+import android.app.Service;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.provider.Settings;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.widget.Button;
+
+/** Service that starts the overlay for the test. */
+public final class OverlayService extends Service {
+    public Button mButton;
+    private WindowManager mWindowManager;
+    private WindowManager.LayoutParams mLayoutParams;
+
+    @Override
+    public void onCreate() {
+        Log.d(Constants.TAG, "onCreate() called");
+        super.onCreate();
+
+        DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics();
+        int scaledWidth = (int) (displayMetrics.widthPixels * 0.9);
+        int scaledHeight = (int) (displayMetrics.heightPixels * 0.9);
+
+        mWindowManager = getSystemService(WindowManager.class);
+        mLayoutParams = new WindowManager.LayoutParams();
+        mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+        mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        mLayoutParams.format = PixelFormat.OPAQUE;
+        mLayoutParams.gravity = Gravity.CENTER;
+        mLayoutParams.width = scaledWidth;
+        mLayoutParams.height = scaledHeight;
+        mLayoutParams.x = scaledWidth / 2;
+        mLayoutParams.y = scaledHeight / 2;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Log.d(Constants.TAG, "onStartCommand() called");
+        showFloatingWindow();
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.d(Constants.TAG, "onDestroy() called");
+        if (mWindowManager != null && mButton != null) {
+            mWindowManager.removeView(mButton);
+        }
+        super.onDestroy();
+    }
+
+    private void showFloatingWindow() {
+        if (!Settings.canDrawOverlays(this)) {
+            Log.w(Constants.TAG, "Cannot show overlay window. Permission denied");
+        }
+
+        mButton = new Button(getApplicationContext());
+        mButton.setText(getResources().getString(R.string.tapjacking_text));
+        mButton.setTag(mButton.getVisibility());
+        mWindowManager.addView(mButton, mLayoutParams);
+
+        new Handler(Looper.myLooper()).postDelayed(this::stopSelf, 60_000);
+        Log.d(Constants.TAG, "Floating window button created");
+    }
+}