blob: 60c7a59d9456178fcab263578ea10932dd0e66e4 [file] [log] [blame]
/*
* Copyright (C) 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 com.android.tests.rollback;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.content.rollback.RollbackManager;
import android.support.test.InstrumentationRegistry;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
/**
* Utilities to facilitate testing rollbacks.
*/
class RollbackTestUtils {
private static final String TAG = "RollbackTest";
static RollbackManager getRollbackManager() {
Context context = InstrumentationRegistry.getContext();
RollbackManager rm = (RollbackManager) context.getSystemService(Context.ROLLBACK_SERVICE);
if (rm == null) {
throw new AssertionError("Failed to get RollbackManager");
}
return rm;
}
/**
* Returns the version of the given package installed on device.
* Returns -1 if the package is not currently installed.
*/
static long getInstalledVersion(String packageName) {
Context context = InstrumentationRegistry.getContext();
PackageManager pm = context.getPackageManager();
try {
PackageInfo info = pm.getPackageInfo(packageName, 0);
return info.getLongVersionCode();
} catch (PackageManager.NameNotFoundException e) {
return -1;
}
}
private static void assertStatusSuccess(Intent result) {
int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
if (status == -1) {
throw new AssertionError("PENDING USER ACTION");
} else if (status > 0) {
String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
}
}
/**
* Uninstalls the given package.
* Does nothing if the package is not installed.
* @throws AssertionError if package can't be uninstalled.
*/
static void uninstall(String packageName) throws InterruptedException, IOException {
// No need to uninstall if the package isn't installed.
if (getInstalledVersion(packageName) == -1) {
return;
}
Context context = InstrumentationRegistry.getContext();
PackageManager packageManager = context.getPackageManager();
PackageInstaller packageInstaller = packageManager.getPackageInstaller();
packageInstaller.uninstall(packageName, LocalIntentSender.getIntentSender());
assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
}
/**
* Commit the given rollback.
* @throws AssertionError if the rollback fails.
*/
static void rollback(int rollbackId, VersionedPackage... causePackages)
throws InterruptedException {
RollbackManager rm = getRollbackManager();
rm.commitRollback(rollbackId, Arrays.asList(causePackages),
LocalIntentSender.getIntentSender());
Intent result = LocalIntentSender.getIntentSenderResult();
int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
RollbackManager.STATUS_FAILURE);
if (status != RollbackManager.STATUS_SUCCESS) {
String message = result.getStringExtra(RollbackManager.EXTRA_STATUS_MESSAGE);
throw new AssertionError(message);
}
}
/**
* Installs the apk with the given name.
*
* @param resourceName name of class loader resource for the apk to
* install.
* @param enableRollback if rollback should be enabled.
* @throws AssertionError if the installation fails.
*/
static void install(String resourceName, boolean enableRollback)
throws InterruptedException, IOException {
Context context = InstrumentationRegistry.getContext();
PackageInstaller.Session session = null;
PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
if (enableRollback) {
params.setEnableRollback();
}
int sessionId = packageInstaller.createSession(params);
session = packageInstaller.openSession(sessionId);
ClassLoader loader = RollbackTest.class.getClassLoader();
try (OutputStream packageInSession = session.openWrite("package", 0, -1);
InputStream is = loader.getResourceAsStream(resourceName);) {
byte[] buffer = new byte[4096];
int n;
while ((n = is.read(buffer)) >= 0) {
packageInSession.write(buffer, 0, n);
}
}
// Commit the session (this will start the installation workflow).
session.commit(LocalIntentSender.getIntentSender());
assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
}
/** Launches {@code packageName} with {@link Intent#ACTION_MAIN}. */
static void launchPackage(String packageName)
throws InterruptedException, IOException {
Context context = InstrumentationRegistry.getContext();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setPackage(packageName);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
context.startActivity(intent);
}
/**
* Installs the apks with the given resource names as an atomic set.
*
* @param enableRollback if rollback should be enabled.
* @param resourceNames names of the class loader resource for the apks to
* install.
* @throws AssertionError if the installation fails.
*/
static void installMultiPackage(boolean enableRollback, String... resourceNames)
throws InterruptedException, IOException {
Context context = InstrumentationRegistry.getContext();
PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams multiPackageParams = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
multiPackageParams.setMultiPackage();
if (enableRollback) {
// TODO: Do we set this on the parent params, the child params, or
// both?
multiPackageParams.setEnableRollback();
}
int multiPackageId = packageInstaller.createSession(multiPackageParams);
PackageInstaller.Session multiPackage = packageInstaller.openSession(multiPackageId);
for (String resourceName : resourceNames) {
PackageInstaller.Session session = null;
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
if (enableRollback) {
params.setEnableRollback();
}
int sessionId = packageInstaller.createSession(params);
session = packageInstaller.openSession(sessionId);
ClassLoader loader = RollbackTest.class.getClassLoader();
try (OutputStream packageInSession = session.openWrite("package", 0, -1);
InputStream is = loader.getResourceAsStream(resourceName);) {
byte[] buffer = new byte[4096];
int n;
while ((n = is.read(buffer)) >= 0) {
packageInSession.write(buffer, 0, n);
}
}
multiPackage.addChildSessionId(sessionId);
}
// Commit the session (this will start the installation workflow).
multiPackage.commit(LocalIntentSender.getIntentSender());
assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
}
static void adoptShellPermissionIdentity(String... permissions) {
InstrumentationRegistry
.getInstrumentation()
.getUiAutomation()
.adoptShellPermissionIdentity(permissions);
}
static void dropShellPermissionIdentity() {
InstrumentationRegistry
.getInstrumentation()
.getUiAutomation()
.dropShellPermissionIdentity();
}
}