blob: 84c26966a3d49717674570627f6de1d22dfb2451 [file] [log] [blame]
/*
* Copyright (C) 2020 Google Inc.
*
* 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.packageinstaller.uninstall.cts;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static com.android.compatibility.common.util.SystemUtil.eventually;
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
import static com.android.compatibility.common.util.UiAutomatorUtils.waitFindObject;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.server.wm.WindowManagerStateHelper;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.AppOpsUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class UninstallPinnedTest {
private static final String APK =
"/data/local/tmp/cts/uninstall/CtsSelfUninstallingTestApp.apk";
private static final String TEST_PKG_NAME = "android.packageinstaller.selfuninstalling.cts";
private static final String TEST_ACTIVITY_NAME = TEST_PKG_NAME + ".SelfUninstallActivity";
private static final String ACTION_SELF_UNINSTALL =
"android.packageinstaller.selfuninstalling.cts.action.SELF_UNINSTALL";
private static final ComponentName COMPONENT = new ComponentName(TEST_PKG_NAME, TEST_ACTIVITY_NAME);
public static final String CALLBACK_ACTION =
"android.packageinstaller.uninstall.cts.action.UNINSTALL_PINNED_CALLBACK";
private WindowManagerStateHelper mWmState = new WindowManagerStateHelper();
private Context mContext;
private UiDevice mUiDevice;
private ActivityTaskManager mActivityTaskManager;
@Before
public void setup() throws Exception {
mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
mActivityTaskManager = mContext.getSystemService(ActivityTaskManager.class);
// Unblock UI
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
if (!mUiDevice.isScreenOn()) {
mUiDevice.wakeUp();
}
mUiDevice.executeShellCommand("wm dismiss-keyguard");
AppOpsUtils.reset(mContext.getPackageName());
runShellCommand("pm install -r --force-queryable " + APK);
Intent i = new Intent()
.setComponent(COMPONENT)
.addFlags(FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(i);
pinActivity(COMPONENT);
}
@Test
public void testAppCantUninstallItself() throws Exception {
mUiDevice.waitForIdle();
eventually(() -> {
mContext.sendBroadcast(new Intent(ACTION_SELF_UNINSTALL));
waitFindObject(By.text("OK")).click();
}, 60000);
mUiDevice.waitForIdle();
Thread.sleep(5000);
assertTrue("Package was uninstalled.", isInstalled());
}
@Test
public void testCantUninstallAppDirectly() {
CompletableFuture<Integer> statusFuture = new CompletableFuture<>();
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
statusFuture.complete(
intent.getIntExtra(PackageInstaller.EXTRA_STATUS, Integer.MAX_VALUE));
}
}, new IntentFilter(CALLBACK_ACTION));
runWithShellPermissionIdentity(() -> {
mContext.getPackageManager().getPackageInstaller().uninstall(TEST_PKG_NAME,
PendingIntent.getBroadcast(mContext, 1,
new Intent(CALLBACK_ACTION),
0).getIntentSender());
});
int status = statusFuture.join();
assertEquals("Wrong code received", PackageInstaller.STATUS_FAILURE_BLOCKED, status);
assertTrue("Package was uninstalled.", isInstalled());
}
@Test
public void testCantUninstallWithShell() throws Exception {
mUiDevice.executeShellCommand("pm uninstall " + TEST_PKG_NAME);
assertTrue("Package was uninstalled.", isInstalled());
}
@After
public void unpinAndUninstall() throws IOException {
runWithShellPermissionIdentity(() -> mActivityTaskManager.stopSystemLockTaskMode());
mUiDevice.executeShellCommand("pm uninstall " + TEST_PKG_NAME);
}
private void pinActivity(ComponentName component) {
mWmState.computeState();
int stackId = mWmState.getStackIdByActivity(component);
runWithShellPermissionIdentity(() -> {
mActivityTaskManager.startSystemLockTaskMode(
stackId);
});
}
private boolean isInstalled() {
try {
mContext.getPackageManager().getPackageInfo(TEST_PKG_NAME, 0);
return true;
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
}