1 /* 2 * Copyright (C) 2020 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.tests.rollback; 18 19 import static com.android.cts.rollback.lib.RollbackInfoSubject.assertThat; 20 import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoForPackage; 21 22 import static com.google.common.truth.Truth.assertThat; 23 24 import android.Manifest; 25 import android.content.ComponentName; 26 import android.content.Intent; 27 import android.content.pm.PackageManager; 28 import android.content.rollback.RollbackManager; 29 import android.os.ParcelFileDescriptor; 30 import android.provider.DeviceConfig; 31 32 import androidx.test.platform.app.InstrumentationRegistry; 33 34 import com.android.cts.install.lib.Install; 35 import com.android.cts.install.lib.InstallUtils; 36 import com.android.cts.install.lib.TestApp; 37 import com.android.cts.rollback.lib.RollbackUtils; 38 39 import libcore.io.IoUtils; 40 41 import org.junit.After; 42 import org.junit.Before; 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 import org.junit.runners.JUnit4; 46 47 import java.io.File; 48 import java.util.concurrent.TimeUnit; 49 50 @RunWith(JUnit4.class) 51 public class NetworkStagedRollbackTest { 52 private static final String NETWORK_STACK_CONNECTOR_CLASS = 53 "android.net.INetworkStackConnector"; 54 private static final String PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS = 55 "watchdog_request_timeout_millis"; 56 57 private static final String[] NETWORK_STACK_APK_NAMES = { 58 "NetworkStack", "NetworkStackGoogle", "NetworkStackNext", "NetworkStackNextGoogle" 59 }; 60 61 private static final TestApp NETWORK_STACK = new TestApp("NetworkStack", 62 getNetworkStackPackageName(), -1, false, findNetworkStackApk()); 63 findNetworkStackApk()64 private static File[] findNetworkStackApk() { 65 for (String name : NETWORK_STACK_APK_NAMES) { 66 final File apk = new File("/system/priv-app/" + name + "/" + name + ".apk"); 67 if (apk.isFile()) { 68 final File dir = new File("/system/priv-app/" + name); 69 return dir.listFiles((d, f) -> f.startsWith(name)); 70 } 71 } 72 throw new RuntimeException("Can't find NetworkStackApk"); 73 } 74 75 /** 76 * Adopts common shell permissions needed for rollback tests. 77 */ 78 @Before adoptShellPermissions()79 public void adoptShellPermissions() { 80 InstallUtils.adoptShellPermissionIdentity( 81 Manifest.permission.INSTALL_PACKAGES, 82 Manifest.permission.DELETE_PACKAGES, 83 Manifest.permission.TEST_MANAGE_ROLLBACKS, 84 Manifest.permission.FORCE_STOP_PACKAGES, 85 Manifest.permission.WRITE_DEVICE_CONFIG); 86 } 87 88 /** 89 * Drops shell permissions needed for rollback tests. 90 */ 91 @After dropShellPermissions()92 public void dropShellPermissions() { 93 InstallUtils.dropShellPermissionIdentity(); 94 } 95 96 @Test cleanUp()97 public void cleanUp() { 98 RollbackManager rm = RollbackUtils.getRollbackManager(); 99 rm.getAvailableRollbacks().stream().flatMap(info -> info.getPackages().stream()) 100 .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage); 101 rm.getRecentlyCommittedRollbacks().stream().flatMap(info -> info.getPackages().stream()) 102 .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage); 103 assertThat(rm.getAvailableRollbacks()).isEmpty(); 104 assertThat(rm.getRecentlyCommittedRollbacks()).isEmpty(); 105 uninstallNetworkStackPackage(); 106 } 107 108 @Test testNetworkFailedRollback_Phase1()109 public void testNetworkFailedRollback_Phase1() throws Exception { 110 // Remove available rollbacks and uninstall NetworkStack on /data/ 111 RollbackManager rm = RollbackUtils.getRollbackManager(); 112 String networkStack = getNetworkStackPackageName(); 113 114 assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), 115 networkStack)).isNull(); 116 117 // Reduce health check deadline 118 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK, 119 PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS, 120 Integer.toString(120000), false); 121 // Simulate re-installation of new NetworkStack with rollbacks enabled 122 installNetworkStackPackage(); 123 } 124 125 @Test testNetworkFailedRollback_Phase2()126 public void testNetworkFailedRollback_Phase2() throws Exception { 127 RollbackManager rm = RollbackUtils.getRollbackManager(); 128 assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), 129 getNetworkStackPackageName())).isNotNull(); 130 131 // Sleep for < health check deadline 132 Thread.sleep(TimeUnit.SECONDS.toMillis(5)); 133 // Verify rollback was not executed before health check deadline 134 assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(), 135 getNetworkStackPackageName())).isNull(); 136 } 137 138 @Test testNetworkFailedRollback_Phase3()139 public void testNetworkFailedRollback_Phase3() throws Exception { 140 RollbackManager rm = RollbackUtils.getRollbackManager(); 141 assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(), 142 getNetworkStackPackageName())).isNotNull(); 143 } 144 getNetworkStackPackageName()145 private static String getNetworkStackPackageName() { 146 Intent intent = new Intent(NETWORK_STACK_CONNECTOR_CLASS); 147 ComponentName comp = intent.resolveSystemService( 148 InstrumentationRegistry.getInstrumentation().getContext().getPackageManager(), 0); 149 return comp.getPackageName(); 150 } 151 installNetworkStackPackage()152 private static void installNetworkStackPackage() throws Exception { 153 Install.single(NETWORK_STACK).setStaged().setEnableRollback() 154 .addInstallFlags(PackageManager.INSTALL_REPLACE_EXISTING).commit(); 155 } 156 uninstallNetworkStackPackage()157 private static void uninstallNetworkStackPackage() { 158 // Uninstall the package as a privileged user so we won't fail due to permission. 159 runShellCommand("pm uninstall " + getNetworkStackPackageName()); 160 } 161 162 @Test testNetworkPassedDoesNotRollback_Phase1()163 public void testNetworkPassedDoesNotRollback_Phase1() throws Exception { 164 // Remove available rollbacks and uninstall NetworkStack on /data/ 165 RollbackManager rm = RollbackUtils.getRollbackManager(); 166 String networkStack = getNetworkStackPackageName(); 167 168 assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), 169 networkStack)).isNull(); 170 171 // Reduce health check deadline, here unlike the network failed case, we use 172 // a longer deadline because joining a network can take a much longer time for 173 // reasons external to the device than 'not joining' 174 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK, 175 PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS, 176 Integer.toString(300000), false); 177 // Simulate re-installation of new NetworkStack with rollbacks enabled 178 installNetworkStackPackage(); 179 } 180 181 @Test testNetworkPassedDoesNotRollback_Phase2()182 public void testNetworkPassedDoesNotRollback_Phase2() throws Exception { 183 RollbackManager rm = RollbackUtils.getRollbackManager(); 184 assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), 185 getNetworkStackPackageName())).isNotNull(); 186 } 187 188 @Test testNetworkPassedDoesNotRollback_Phase3()189 public void testNetworkPassedDoesNotRollback_Phase3() throws Exception { 190 // Sleep for > health check deadline. We expect no rollback should happen during sleeping. 191 // If the device reboots for rollback, this device test will fail as well as the host test. 192 Thread.sleep(TimeUnit.SECONDS.toMillis(310)); 193 RollbackManager rm = RollbackUtils.getRollbackManager(); 194 assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(), 195 getNetworkStackPackageName())).isNull(); 196 } 197 runShellCommand(String cmd)198 private static void runShellCommand(String cmd) { 199 ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation() 200 .executeShellCommand(cmd); 201 IoUtils.closeQuietly(pfd); 202 } 203 } 204