blob: f9c4ba8098463f36a2f6fb04e01dd635c165d57f [file] [log] [blame]
/*
* Copyright (C) 2019 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.stagedinstall;
import static com.android.tests.stagedinstall.PackageInstallerSessionInfoSubject.assertThat;
import static com.google.common.truth.Truth.assertThat;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.TimeUnit;
/**
* These tests use a similar structure to {@link StagedInstallTest}. See
* {@link StagedInstallTest} documentation for reference.
*
* @see StagedInstallTest
*/
@RunWith(JUnit4.class)
public class ApexShimValidationTest {
private static final String SHIM_APEX_PACKAGE_NAME = "com.android.apex.cts.shim";
@Before
public void adoptShellPermissions() {
InstrumentationRegistry
.getInstrumentation()
.getUiAutomation()
.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES);
}
@After
public void dropShellPermissions() {
InstrumentationRegistry
.getInstrumentation()
.getUiAutomation()
.dropShellPermissionIdentity();
}
@Before
public void clearBroadcastReceiver() {
SessionUpdateBroadcastReceiver.sessionBroadcasts.clear();
}
@Test
public void testRejectsApexWithAdditionalFile_Commit() throws Exception {
int sessionId = stageApex("com.android.apex.cts.shim.v2_additional_file.apex");
PackageInstaller.SessionInfo info =
SessionUpdateBroadcastReceiver.sessionBroadcasts.poll(60, TimeUnit.SECONDS);
assertThat(info.getSessionId()).isEqualTo(sessionId);
assertThat(info).isStagedSessionFailed();
}
@Test
public void testRejectsApexWithAdditionalFolder_Commit() throws Exception {
int sessionId = stageApex("com.android.apex.cts.shim.v2_additional_folder.apex");
PackageInstaller.SessionInfo info =
SessionUpdateBroadcastReceiver.sessionBroadcasts.poll(60, TimeUnit.SECONDS);
assertThat(info.getSessionId()).isEqualTo(sessionId);
assertThat(info).isStagedSessionFailed();
}
@Test
public void testRejectsApexWithPostInstallHook_Commit() throws Exception {
int sessionId = stageApex("com.android.apex.cts.shim.v2_with_post_install_hook.apex");
PackageInstaller.SessionInfo info =
SessionUpdateBroadcastReceiver.sessionBroadcasts.poll(60, TimeUnit.SECONDS);
assertThat(info.getSessionId()).isEqualTo(sessionId);
assertThat(info).isStagedSessionFailed();
}
@Test
public void testRejectsApexWithPreInstallHook_Commit() throws Exception {
int sessionId = stageApex("com.android.apex.cts.shim.v2_with_pre_install_hook.apex");
PackageInstaller.SessionInfo info =
SessionUpdateBroadcastReceiver.sessionBroadcasts.poll(60, TimeUnit.SECONDS);
assertThat(info.getSessionId()).isEqualTo(sessionId);
assertThat(info).isStagedSessionFailed();
}
@Test
public void testRejectsApexWrongSHA_Commit() throws Exception {
int sessionId = stageApex("com.android.apex.cts.shim.v2_wrong_sha.apex");
PackageInstaller.SessionInfo info =
SessionUpdateBroadcastReceiver.sessionBroadcasts.poll(60, TimeUnit.SECONDS);
assertThat(info.getSessionId()).isEqualTo(sessionId);
assertThat(info).isStagedSessionFailed();
}
@Test
public void testInstallRejected_VerifyPostReboot() throws Exception {
assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
}
private static PackageInstaller getPackageInstaller() {
return InstrumentationRegistry.getInstrumentation().getContext().getPackageManager()
.getPackageInstaller();
}
private static long getInstalledVersion(String packageName) {
Context context = InstrumentationRegistry.getInstrumentation().getContext();
PackageManager pm = context.getPackageManager();
try {
PackageInfo info = pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
return info.getLongVersionCode();
} catch (PackageManager.NameNotFoundException e) {
return -1;
}
}
private static int stageApex(String apexFileName) throws Exception {
PackageInstaller installer = getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.setInstallAsApex();
params.setStaged();
int sessionId = installer.createSession(params);
PackageInstaller.Session session = installer.openSession(sessionId);
writeApex(session, apexFileName);
session.commit(LocalIntentSender.getIntentSender());
Intent result = LocalIntentSender.getIntentSenderResult();
assertStatusSuccess(result);
return sessionId;
}
private static void writeApex(PackageInstaller.Session session, String apkFileName)
throws Exception {
try (OutputStream packageInSession = session.openWrite(apkFileName, 0, -1);
InputStream is =
ApexShimValidationTest.class.getClassLoader().getResourceAsStream(
apkFileName)) {
byte[] buffer = new byte[4096];
int n;
while ((n = is.read(buffer)) >= 0) {
packageInSession.write(buffer, 0, n);
}
}
}
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);
}
}
}