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.tests.apex;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static com.google.common.truth.Truth.assertWithMessage;
21 
22 import static org.junit.Assume.assumeTrue;
23 
24 import android.cts.install.lib.host.InstallUtilsHost;
25 import android.platform.test.annotations.RequiresDevice;
26 
27 import com.android.tests.rollback.host.AbandonSessionsRule;
28 import com.android.tradefed.config.Option;
29 import com.android.tradefed.config.Option.Importance;
30 import com.android.tradefed.device.ITestDevice.ApexInfo;
31 import com.android.tradefed.log.LogUtil.CLog;
32 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
33 
34 import org.junit.After;
35 import org.junit.Assert;
36 import org.junit.Before;
37 import org.junit.Rule;
38 import org.junit.Test;
39 
40 import java.io.File;
41 import java.time.Duration;
42 import java.util.List;
43 import java.util.Set;
44 
45 /**
46  * Base test to check if Apex can be staged, activated and uninstalled successfully.
47  */
48 public abstract class ApexE2EBaseHostTest extends BaseHostJUnit4Test {
49 
50     private static final String OPTION_APEX_FILE_NAME = "apex_file_name";
51 
52     private static final Duration BOOT_COMPLETE_TIMEOUT = Duration.ofMinutes(2);
53 
54     private static final String USERSPACE_REBOOT_SUPPORTED_PROP =
55             "init.userspace_reboot.is_supported";
56 
57     // Protected so that derived tests can have access to test utils automatically
58     protected final InstallUtilsHost mHostUtils = new InstallUtilsHost(this);
59 
60     @Rule
61     public AbandonSessionsRule mHostTestRule = new AbandonSessionsRule(this);
62 
63     @Option(name = OPTION_APEX_FILE_NAME,
64             description = "The file name of the apex module.",
65             importance = Importance.IF_UNSET,
66             mandatory = true
67     )
68     protected String mApexFileName = null;
69 
70     @Before
setUp()71     public void setUp() throws Exception {
72         assumeTrue("Updating APEX is not supported", mHostUtils.isApexUpdateSupported());
73         uninstallAllApexes();
74     }
75 
76     @After
tearDown()77     public void tearDown() throws Exception {
78         assumeTrue("Updating APEX is not supported", mHostUtils.isApexUpdateSupported());
79         uninstallAllApexes();
80     }
81 
getAllApexFilenames()82     protected List<String> getAllApexFilenames() {
83         return List.of(mApexFileName);
84     }
85 
86     @Test
testStageActivateUninstallApexPackage()87     public final void testStageActivateUninstallApexPackage()  throws Exception {
88         stageActivateUninstallApexPackage(false/*userspaceReboot*/);
89     }
90 
91     @Test
92     @RequiresDevice // TODO(b/147726967): Remove when Userspace reboot works on cuttlefish
testStageActivateUninstallApexPackageWithUserspaceReboot()93     public final void testStageActivateUninstallApexPackageWithUserspaceReboot()  throws Exception {
94         assumeTrue("Userspace reboot not supported on the device",
95                 getDevice().getBooleanProperty(USERSPACE_REBOOT_SUPPORTED_PROP, false));
96         stageActivateUninstallApexPackage(true/*userspaceReboot*/);
97     }
98 
stageActivateUninstallApexPackage(boolean userspaceReboot)99     private void stageActivateUninstallApexPackage(boolean userspaceReboot)  throws Exception {
100         ApexInfo apex = installApex(mApexFileName);
101 
102         reboot(userspaceReboot); // for install to take affect
103         Set<ApexInfo> activatedApexes = getDevice().getActiveApexes();
104         assertWithMessage("Failed to activate %s", apex).that(activatedApexes).contains(apex);
105 
106         additionalCheck();
107     }
108 
uninstallAllApexes()109     private void uninstallAllApexes() throws Exception {
110         for (String filename : getAllApexFilenames()) {
111             ApexInfo apex = mHostUtils.getApexInfo(mHostUtils.getTestFile(filename));
112             uninstallApex(apex.name);
113         }
114     }
115 
installApex(String filename)116     protected final ApexInfo installApex(String filename) throws Exception {
117         File testAppFile = mHostUtils.getTestFile(filename);
118 
119         String installResult = mHostUtils.installStagedPackage(testAppFile);
120         assertWithMessage("failed to install test app %s. Reason: %s", filename, installResult)
121                 .that(installResult).isNull();
122 
123         ApexInfo testApexInfo = mHostUtils.getApexInfo(testAppFile);
124         Assert.assertNotNull(testApexInfo);
125         return testApexInfo;
126     }
127 
reboot(boolean userspaceReboot)128     protected final void reboot(boolean userspaceReboot) throws Exception {
129         if (userspaceReboot) {
130             assertThat(getDevice().setProperty("test.userspace_reboot.requested", "1")).isTrue();
131             getDevice().rebootUserspace();
132         } else {
133             getDevice().reboot();
134         }
135         boolean success = getDevice().waitForBootComplete(BOOT_COMPLETE_TIMEOUT.toMillis());
136         assertWithMessage("Device didn't boot in %s", BOOT_COMPLETE_TIMEOUT).that(success).isTrue();
137         if (userspaceReboot) {
138             // If userspace reboot fails and fallback to hard reboot is triggered then
139             // test.userspace_reboot.requested won't be set.
140             boolean res = getDevice().getBooleanProperty("test.userspace_reboot.requested", false);
141             String message = "Userspace reboot failed, fallback to full reboot was triggered. ";
142             message += "Boot reason: " + getDevice().getProperty("sys.boot.reason.last");
143             assertWithMessage(message).that(res).isTrue();
144         }
145     }
146 
147     /**
148      * Do some additional check, invoked by {@link #testStageActivateUninstallApexPackage()}.
149      */
additionalCheck()150     public void additionalCheck() throws Exception {};
151 
uninstallApex(String apexName)152     protected final void uninstallApex(String apexName) throws Exception {
153         String res = getDevice().uninstallPackage(apexName);
154         if (res != null) {
155             // Uninstall failed. Most likely this means that there were no apex installed. No need
156             // to reboot.
157             CLog.i("Uninstall of %s failed: %s, likely already on factory version", apexName, res);
158         } else {
159             // Uninstall succeeded. Need to reboot.
160             getDevice().reboot(); // for the uninstall to take affect
161         }
162     }
163 }
164