blob: b69a60c684f69972a56e5e434e6cce79ca73b98d [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.cts.deviceowner;
import static android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID;
import android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import com.android.compatibility.common.util.SystemUtil;
import java.io.File;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Test {@link android.app.admin.DevicePolicyManager#installSystemUpdate}
*/
public class InstallUpdateTest extends BaseDeviceOwnerTest {
private static final int BATTERY_STATE_CHANGE_TIMEOUT_MS = 5000;
private static final int BATTERY_STATE_CHANGE_SLEEP_PER_CHECK_MS = 50;
private static final int TEST_BATTERY_THRESHOLD = 10;
private static final IntentFilter BATTERY_CHANGED_FILTER =
new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
private static final String AB_DEVICE_KEY = "ro.build.ab_update";
public static final String TEST_SYSTEM_UPDATES_DIR =
"/data/local/tmp/cts/deviceowner/";
public static final int TIMEOUT = 5;
private int callbackErrorCode;
public void testInstallUpdate_failFileNotFound() throws InterruptedException {
assertUpdateError(
"random",
InstallSystemUpdateCallback.UPDATE_ERROR_FILE_NOT_FOUND);
}
public void testInstallUpdate_failNoZipOtaFile() throws InterruptedException {
if (!isDeviceAB()) {
return;
}
assertUpdateError("notZip.zi", UPDATE_ERROR_UPDATE_FILE_INVALID);
}
public void testInstallUpdate_failWrongPayloadFile() throws InterruptedException {
if (!isDeviceAB()) {
return;
}
assertUpdateError("wrongPayload.zip", UPDATE_ERROR_UPDATE_FILE_INVALID);
}
public void testInstallUpdate_failEmptyOtaFile() throws InterruptedException {
if (!isDeviceAB()) {
return;
}
assertUpdateError("empty.zip", UPDATE_ERROR_UPDATE_FILE_INVALID);
}
public void testInstallUpdate_failWrongHash() throws InterruptedException {
if (!isDeviceAB()) {
return;
}
assertUpdateError("wrongHash.zip", UPDATE_ERROR_UPDATE_FILE_INVALID);
}
public void testInstallUpdate_failWrongSize() throws InterruptedException {
if (!isDeviceAB()) {
return;
}
assertUpdateError("wrongSize.zip", UPDATE_ERROR_UPDATE_FILE_INVALID);
}
public void testInstallUpdate_notCharging_belowThreshold_failsBatteryCheck() throws Exception {
try {
setNonChargingBatteryThreshold(TEST_BATTERY_THRESHOLD);
setNonChargingBatteryLevelAndWait(TEST_BATTERY_THRESHOLD - 1);
assertUpdateError("wrongSize.zip",
InstallSystemUpdateCallback.UPDATE_ERROR_BATTERY_LOW);
} finally {
resetBatteryState();
resetDevicePolicyConstants();
}
}
public void testInstallUpdate_notCharging_aboveThreshold_passesBatteryCheck() throws Exception {
if (!isDeviceAB()) {
return;
}
try {
setNonChargingBatteryThreshold(TEST_BATTERY_THRESHOLD);
setNonChargingBatteryLevelAndWait(TEST_BATTERY_THRESHOLD);
// Positive CTS tests aren't possible, so we verify that we get the file-related error
// rather than the battery one.
assertUpdateError("wrongSize.zip", UPDATE_ERROR_UPDATE_FILE_INVALID);
} finally {
resetBatteryState();
resetDevicePolicyConstants();
}
}
public void testInstallUpdate_charging_belowThreshold_failsBatteryCheck() throws Exception {
try {
setChargingBatteryThreshold(TEST_BATTERY_THRESHOLD);
setChargingBatteryLevelAndWait(TEST_BATTERY_THRESHOLD - 1);
assertUpdateError("wrongSize.zip",
InstallSystemUpdateCallback.UPDATE_ERROR_BATTERY_LOW);
} finally {
resetBatteryState();
resetDevicePolicyConstants();
}
}
public void testInstallUpdate_charging_aboveThreshold_passesBatteryCheck() throws Exception {
if (!isDeviceAB()) {
return;
}
try {
setChargingBatteryThreshold(TEST_BATTERY_THRESHOLD);
setChargingBatteryLevelAndWait(TEST_BATTERY_THRESHOLD);
// Positive CTS tests aren't possible, so we verify that we get the file-related error
// rather than the battery one.
assertUpdateError("wrongSize.zip", UPDATE_ERROR_UPDATE_FILE_INVALID);
} finally {
resetBatteryState();
resetDevicePolicyConstants();
}
}
private void assertUpdateError(String fileName, int expectedErrorCode)
throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
Uri uri = Uri.fromFile(new File(TEST_SYSTEM_UPDATES_DIR, fileName));
mDevicePolicyManager.installSystemUpdate(getWho(), uri,
Runnable::run, new InstallSystemUpdateCallback() {
@Override
public void onInstallUpdateError(int errorCode, String errorMessage) {
callbackErrorCode = errorCode;
latch.countDown();
}
});
assertTrue(latch.await(TIMEOUT, TimeUnit.MINUTES));
assertEquals(expectedErrorCode, callbackErrorCode);
}
private void setNonChargingBatteryThreshold(int threshold) {
SystemUtil.runShellCommand(
"settings put global device_policy_constants battery_threshold_not_charging="
+ threshold);
}
private void setNonChargingBatteryLevelAndWait(int level) throws Exception {
setBatteryStateAndWait(/* plugged= */ false, level);
}
private void setChargingBatteryThreshold(int threshold) {
SystemUtil.runShellCommand(
"settings put global device_policy_constants battery_threshold_charging="
+ threshold);
}
private void setChargingBatteryLevelAndWait(int level) throws Exception {
setBatteryStateAndWait(/* plugged= */ true, level);
}
/** Should be paired with {@link #resetBatteryState()} in a {@code finally} block. */
private void setBatteryStateAndWait(boolean plugged, int level) throws Exception {
SystemUtil.runShellCommand(plugged ? "cmd battery set ac 1" : "cmd battery unplug");
SystemUtil.runShellCommand("cmd battery set -f level " + level);
long startTime = SystemClock.elapsedRealtime();
while (!isBatteryState(plugged, level)
&& SystemClock.elapsedRealtime() <= startTime + BATTERY_STATE_CHANGE_TIMEOUT_MS) {
Thread.sleep(BATTERY_STATE_CHANGE_SLEEP_PER_CHECK_MS);
}
}
private boolean isBatteryState(boolean plugged, int level) {
final Intent batteryStatus =
mContext.registerReceiver(/* receiver= */ null, BATTERY_CHANGED_FILTER);
return isPluggedIn(batteryStatus) == plugged
&& calculateBatteryPercentage(batteryStatus) == level;
}
private boolean isPluggedIn(Intent batteryStatus) {
return batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, /* defaultValue= */ -1) > 0;
}
private float calculateBatteryPercentage(Intent batteryStatus) {
int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, /* defaultValue= */ -1);
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, /* defaultValue= */ -1);
return 100 * level / (float) scale;
}
private void resetBatteryState() {
SystemUtil.runShellCommand("dumpsys battery reset");
}
private void resetDevicePolicyConstants() {
SystemUtil.runShellCommand("settings delete global device_policy_constants");
}
private boolean isDeviceAB() {
return "true".equalsIgnoreCase(SystemProperties.get(AB_DEVICE_KEY, ""));
}
}