1 /*
2  * Copyright (C) 2017 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 android.cts.backup;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertTrue;
21 import static org.junit.Assume.assumeTrue;
22 
23 import android.platform.test.annotations.AppModeFull;
24 
25 import com.android.compatibility.common.util.BackupUtils;
26 import com.android.compatibility.common.util.LogcatInspector;
27 import com.android.tradefed.device.DeviceNotAvailableException;
28 import com.android.tradefed.device.ITestDevice;
29 import com.android.tradefed.log.LogUtil.CLog;
30 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
31 import com.android.tradefed.testtype.ITestInformationReceiver;
32 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
33 
34 import org.junit.After;
35 import org.junit.AssumptionViolatedException;
36 import org.junit.Before;
37 import org.junit.Rule;
38 import org.junit.rules.TestRule;
39 import org.junit.runner.Description;
40 import org.junit.runner.RunWith;
41 import org.junit.runners.model.Statement;
42 
43 import java.io.ByteArrayInputStream;
44 import java.io.IOException;
45 import java.io.InputStream;
46 import java.nio.charset.StandardCharsets;
47 import java.util.regex.Matcher;
48 import java.util.regex.Pattern;
49 
50 /**
51  * Base class for CTS backup/restore hostside tests
52  */
53 @RunWith(DeviceJUnit4ClassRunner.class)
54 @AppModeFull
55 public abstract class BaseBackupHostSideTest extends BaseHostJUnit4Test {
56     /** Value of PackageManager.FEATURE_BACKUP */
57     private static final String FEATURE_BACKUP = "android.software.backup";
58 
59     protected static final String LOCAL_TRANSPORT =
60             "com.android.localtransport/.LocalTransport";
61 
62     @Rule
63     public final RequiredFeatureRule mBackupRequiredRule = new RequiredFeatureRule(this,
64             FEATURE_BACKUP);
65 
66     private BackupUtils mBackupUtils = new BackupUtils() {
67         @Override
68         protected InputStream executeShellCommand(String command) throws IOException {
69             return executeDeviceShellCommand(getDevice(), command);
70         }
71     };
72 
73     protected final LogcatInspector mLogcatInspector = new LogcatInspector() {
74         @Override
75         protected InputStream executeShellCommand(String command) throws IOException {
76             return executeDeviceShellCommand(getDevice(), command);
77         }
78     };
79 
80     @Before
setUp()81     public void setUp() throws Exception {
82         // Check that the backup wasn't disabled and the transport wasn't switched unexpectedly.
83         assertTrue("Backup was unexpectedly disabled during the module test run",
84                 getBackupUtils().isBackupEnabled());
85         assertEquals("LocalTransport should be selected at this point", LOCAL_TRANSPORT,
86                 getCurrentTransport());
87         mBackupUtils.wakeAndUnlockDevice();
88     }
89 
getBackupUtils()90     protected BackupUtils getBackupUtils() {
91         return mBackupUtils;
92     }
93 
94     /**
95      * Attempts to clear the device log.
96      */
clearLogcat()97     protected void clearLogcat() throws DeviceNotAvailableException {
98         getDevice().executeAdbCommand("logcat", "-c");
99     }
100 
101     /**
102      * Run test <testName> in test <className> found in package <packageName> on the device, and
103      * assert it is successful.
104      */
checkDeviceTest(String packageName, String className, String testName)105     protected void checkDeviceTest(String packageName, String className, String testName)
106             throws DeviceNotAvailableException {
107         boolean result = runDeviceTests(packageName, className, testName);
108         assertTrue("Device test failed: " + testName, result);
109     }
110 
startActivityInPackageAndWait(String packageName, String className)111     protected void startActivityInPackageAndWait(String packageName, String className)
112             throws DeviceNotAvailableException {
113         getDevice().executeShellCommand(String.format(
114                 "am start -W -a android.intent.action.MAIN -n %s/%s.%s", packageName,
115                 packageName,
116                 className));
117     }
118 
119     /**
120      * Clears backup data stored in Local Transport for a package.
121      * NB: 'bmgr wipe' does not produce any useful output if the package or transport not found,
122      * so we cannot really check the success of the operation
123      */
clearBackupDataInLocalTransport(String packageName)124     protected void clearBackupDataInLocalTransport(String packageName)
125             throws DeviceNotAvailableException {
126         getDevice().executeShellCommand(
127                 String.format("bmgr wipe %s %s", LOCAL_TRANSPORT, packageName));
128     }
129 
130     /**
131      * Clears package data
132      */
clearPackageData(String packageName)133     protected void clearPackageData(String packageName) throws DeviceNotAvailableException {
134         getDevice().executeShellCommand(String.format("pm clear %s", packageName));
135     }
136 
getCurrentTransport()137     protected String getCurrentTransport() throws DeviceNotAvailableException {
138         String output = getDevice().executeShellCommand("bmgr list transports");
139         Pattern pattern = Pattern.compile("\\* (.*)");
140         Matcher matcher = pattern.matcher(output);
141         if (matcher.find()) {
142             return matcher.group(1);
143         } else {
144             throw new RuntimeException("non-parsable output setting bmgr transport: " + output);
145         }
146     }
147 
setLocalTransportParameters(String parameters)148     protected void setLocalTransportParameters(String parameters) throws Exception {
149         getDevice().executeShellCommand("settings put secure backup_local_transport_parameters "
150                 + parameters);
151     }
152 
getLocalTransportParameters()153     protected String getLocalTransportParameters() throws DeviceNotAvailableException {
154         return getDevice().executeShellCommand(
155                 "settings get secure backup_local_transport_parameters");
156     }
157 
enableFakeEncryptionOnTransport()158     protected void enableFakeEncryptionOnTransport() throws Exception {
159         setLocalTransportParameters("fake_encryption_flag=true");
160     }
161 
disableFakeEncryptionOnTransport()162     protected void disableFakeEncryptionOnTransport() throws Exception {
163         setLocalTransportParameters("fake_encryption_flag=false");
164     }
165 
executeDeviceShellCommand( ITestDevice device, String command)166     static InputStream executeDeviceShellCommand(
167             ITestDevice device, String command) throws IOException {
168         try {
169             String result = device.executeShellCommand(command);
170             return new ByteArrayInputStream(result.getBytes(StandardCharsets.UTF_8));
171         } catch (DeviceNotAvailableException e) {
172             throw new IOException(e);
173         }
174     }
175 
176     // TODO(b/169341308): move to common infra code
177     private static final class RequiredFeatureRule implements TestRule {
178 
179         private final ITestInformationReceiver mReceiver;
180         private final String mFeature;
181 
RequiredFeatureRule(ITestInformationReceiver receiver, String feature)182         RequiredFeatureRule(ITestInformationReceiver receiver, String feature) {
183             mReceiver = receiver;
184             mFeature = feature;
185         }
186 
187         @Override
apply(Statement base, Description description)188         public Statement apply(Statement base, Description description) {
189             return new Statement() {
190 
191                 @Override
192                 public void evaluate() throws Throwable {
193                     boolean hasFeature = false;
194                     try {
195                         hasFeature = mReceiver.getTestInformation().getDevice()
196                                 .hasFeature(mFeature);
197                     } catch (DeviceNotAvailableException e) {
198                         CLog.e("Could not check if device has feature %s: %e", mFeature, e);
199                         return;
200                     }
201 
202                     if (!hasFeature) {
203                         CLog.d("skipping %s#%s"
204                                 + " because device does not have feature '%s'",
205                                 description.getClassName(), description.getMethodName(), mFeature);
206                         throw new AssumptionViolatedException("Device does not have feature '"
207                                 + mFeature + "'");
208                     }
209                     base.evaluate();
210                 }
211             };
212         }
213 
214         @Override
toString()215         public String toString() {
216             return "RequiredFeatureRule[" + mFeature + "]";
217         }
218     }
219 }
220