Home | History | Annotate | Download | only in deviceowner
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.cts.deviceowner;
     18 
     19 import android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback;
     20 import android.content.Intent;
     21 import android.content.IntentFilter;
     22 import android.net.Uri;
     23 import android.os.BatteryManager;
     24 import android.os.SystemClock;
     25 import android.os.SystemProperties;
     26 
     27 import com.android.compatibility.common.util.SystemUtil;
     28 
     29 import java.io.File;
     30 import java.util.concurrent.CountDownLatch;
     31 import java.util.concurrent.TimeUnit;
     32 
     33 /**
     34  * Test {@link android.app.admin.DevicePolicyManager#installSystemUpdate}
     35  */
     36 public class InstallUpdateTest extends BaseDeviceOwnerTest {
     37     private static final int BATTERY_STATE_CHANGE_TIMEOUT_MS = 5000;
     38     private static final int BATTERY_STATE_CHANGE_SLEEP_PER_CHECK_MS = 50;
     39     private static final int TEST_BATTERY_THRESHOLD = 10;
     40     private static final IntentFilter BATTERY_CHANGED_FILTER =
     41             new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
     42     private static final String AB_DEVICE_KEY = "ro.build.ab_update";
     43 
     44     public static final String TEST_SYSTEM_UPDATES_DIR =
     45             "/data/local/tmp/cts/deviceowner/";
     46     public static final int TIMEOUT = 5;
     47 
     48     private int callbackErrorCode;
     49 
     50     public void testInstallUpdate_failFileNotFound() throws InterruptedException {
     51         assertUpdateError(
     52                 "random",
     53                 InstallSystemUpdateCallback.UPDATE_ERROR_FILE_NOT_FOUND);
     54     }
     55 
     56     public void testInstallUpdate_failNoZipOtaFile() throws InterruptedException {
     57         assertUpdateError("notZip.zi",
     58                 isDeviceAB()
     59                         ? InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID
     60                         : InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
     61     }
     62 
     63     public void testInstallUpdate_failWrongPayloadFile() throws InterruptedException {
     64         assertUpdateError("wrongPayload.zip",
     65                 isDeviceAB()
     66                         ? InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID
     67                         : InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
     68     }
     69 
     70     public void testInstallUpdate_failEmptyOtaFile() throws InterruptedException {
     71         assertUpdateError("empty.zip",
     72                 isDeviceAB()
     73                         ? InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID
     74                         : InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
     75     }
     76 
     77     public void testInstallUpdate_failWrongHash() throws InterruptedException {
     78         assertUpdateError("wrongHash.zip",
     79                 isDeviceAB()
     80                         ? InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID
     81                         : InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
     82     }
     83 
     84     public void testInstallUpdate_failWrongSize() throws InterruptedException {
     85         assertUpdateError("wrongSize.zip",
     86                 isDeviceAB()
     87                         ? InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID
     88                         : InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
     89     }
     90 
     91     public void testInstallUpdate_notCharging_belowThreshold_failsBatteryCheck() throws Exception {
     92         try {
     93             setNonChargingBatteryThreshold(TEST_BATTERY_THRESHOLD);
     94             setNonChargingBatteryLevelAndWait(TEST_BATTERY_THRESHOLD - 1);
     95             assertUpdateError("wrongSize.zip",
     96                     InstallSystemUpdateCallback.UPDATE_ERROR_BATTERY_LOW);
     97         } finally {
     98             resetBatteryState();
     99             resetDevicePolicyConstants();
    100         }
    101     }
    102 
    103     public void testInstallUpdate_notCharging_aboveThreshold_passesBatteryCheck() throws Exception {
    104         try {
    105             setNonChargingBatteryThreshold(TEST_BATTERY_THRESHOLD);
    106             setNonChargingBatteryLevelAndWait(TEST_BATTERY_THRESHOLD);
    107             // Positive CTS tests aren't possible, so we verify that we get the file-related error
    108             // rather than the battery one.
    109             assertUpdateError("wrongSize.zip",
    110                     isDeviceAB()
    111                             ? InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID
    112                             : InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
    113         } finally {
    114             resetBatteryState();
    115             resetDevicePolicyConstants();
    116         }
    117     }
    118 
    119     public void testInstallUpdate_charging_belowThreshold_failsBatteryCheck() throws Exception {
    120         try {
    121             setChargingBatteryThreshold(TEST_BATTERY_THRESHOLD);
    122             setChargingBatteryLevelAndWait(TEST_BATTERY_THRESHOLD - 1);
    123             assertUpdateError("wrongSize.zip",
    124                     InstallSystemUpdateCallback.UPDATE_ERROR_BATTERY_LOW);
    125         } finally {
    126             resetBatteryState();
    127             resetDevicePolicyConstants();
    128         }
    129     }
    130 
    131     public void testInstallUpdate_charging_aboveThreshold_passesBatteryCheck() throws Exception {
    132         try {
    133             setChargingBatteryThreshold(TEST_BATTERY_THRESHOLD);
    134             setChargingBatteryLevelAndWait(TEST_BATTERY_THRESHOLD);
    135             // Positive CTS tests aren't possible, so we verify that we get the file-related error
    136             // rather than the battery one.
    137             assertUpdateError("wrongSize.zip",
    138                     isDeviceAB()
    139                             ? InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID
    140                             : InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
    141         } finally {
    142             resetBatteryState();
    143             resetDevicePolicyConstants();
    144         }
    145     }
    146 
    147     private void assertUpdateError(String fileName, int expectedErrorCode)
    148             throws InterruptedException {
    149         CountDownLatch latch = new CountDownLatch(1);
    150         Uri uri = Uri.fromFile(new File(TEST_SYSTEM_UPDATES_DIR, fileName));
    151         mDevicePolicyManager.installSystemUpdate(getWho(), uri,
    152                 Runnable::run, new InstallSystemUpdateCallback() {
    153                     @Override
    154                     public void onInstallUpdateError(int errorCode, String errorMessage) {
    155                         callbackErrorCode = errorCode;
    156                         latch.countDown();
    157                     }
    158                 });
    159         assertTrue(latch.await(TIMEOUT, TimeUnit.MINUTES));
    160         assertEquals(expectedErrorCode, callbackErrorCode);
    161     }
    162 
    163     private void setNonChargingBatteryThreshold(int threshold) {
    164         SystemUtil.runShellCommand(
    165                 "settings put global device_policy_constants battery_threshold_not_charging="
    166                         + threshold);
    167     }
    168 
    169     private void setNonChargingBatteryLevelAndWait(int level) throws Exception {
    170         setBatteryStateAndWait(/* plugged= */ false, level);
    171     }
    172 
    173     private void setChargingBatteryThreshold(int threshold) {
    174         SystemUtil.runShellCommand(
    175                 "settings put global device_policy_constants battery_threshold_charging="
    176                         + threshold);
    177     }
    178 
    179     private void setChargingBatteryLevelAndWait(int level) throws Exception {
    180         setBatteryStateAndWait(/* plugged= */ true, level);
    181     }
    182 
    183     /** Should be paired with {@link #resetBatteryState()} in a {@code finally} block. */
    184     private void setBatteryStateAndWait(boolean plugged, int level) throws Exception {
    185         SystemUtil.runShellCommand(plugged ? "cmd battery set ac 1" : "cmd battery unplug");
    186         SystemUtil.runShellCommand("cmd battery set -f level " + level);
    187         long startTime = SystemClock.elapsedRealtime();
    188         while (!isBatteryState(plugged, level)
    189                 && SystemClock.elapsedRealtime() <= startTime + BATTERY_STATE_CHANGE_TIMEOUT_MS) {
    190             Thread.sleep(BATTERY_STATE_CHANGE_SLEEP_PER_CHECK_MS);
    191         }
    192     }
    193 
    194     private boolean isBatteryState(boolean plugged, int level) {
    195         final Intent batteryStatus =
    196                 mContext.registerReceiver(/* receiver= */ null, BATTERY_CHANGED_FILTER);
    197         return isPluggedIn(batteryStatus) == plugged
    198                 && calculateBatteryPercentage(batteryStatus) == level;
    199     }
    200 
    201     private boolean isPluggedIn(Intent batteryStatus) {
    202         return batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, /* defaultValue= */ -1) > 0;
    203     }
    204 
    205     private float calculateBatteryPercentage(Intent batteryStatus) {
    206         int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, /* defaultValue= */ -1);
    207         int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, /* defaultValue= */ -1);
    208         return 100 * level / (float) scale;
    209     }
    210 
    211     private void resetBatteryState() {
    212         SystemUtil.runShellCommand("dumpsys battery reset");
    213     }
    214 
    215     private void resetDevicePolicyConstants() {
    216         SystemUtil.runShellCommand("settings delete global device_policy_constants");
    217     }
    218 
    219     private boolean isDeviceAB() {
    220         return "true".equalsIgnoreCase(SystemProperties.get(AB_DEVICE_KEY, ""));
    221     }
    222 }
    223