• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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.framework.tests;
18 
19 import com.android.tradefed.device.DeviceNotAvailableException;
20 import com.android.tradefed.device.ITestDevice;
21 import com.android.tradefed.log.LogUtil.CLog;
22 
23 import org.junit.Assert;
24 import org.w3c.dom.Document;
25 import org.w3c.dom.Node;
26 
27 import java.io.File;
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
30 
31 import javax.xml.parsers.DocumentBuilder;
32 import javax.xml.parsers.DocumentBuilderFactory;
33 import javax.xml.xpath.XPath;
34 import javax.xml.xpath.XPathConstants;
35 import javax.xml.xpath.XPathExpression;
36 import javax.xml.xpath.XPathFactory;
37 /** Utility method used for PackageMangerOTATests. Requires adb root. */
38 public class PackageManagerOTATestUtils {
39     public static final String USERDATA_PARTITION = "userdata";
40     public static final String PACKAGE_XML_FILE = "/data/system/packages.xml";
41 
42     private ITestDevice mDevice = null;
43 
44     /**
45      * Constructor.
46      *
47      * @param device the {@link ITestDevice} to use when performing operations.
48      * @throws DeviceNotAvailableException
49      */
PackageManagerOTATestUtils(ITestDevice device)50     public PackageManagerOTATestUtils(ITestDevice device) throws DeviceNotAvailableException {
51         mDevice = device;
52     }
53 
54     /**
55      * Wipe userdata partition on device.
56      *
57      * @throws DeviceNotAvailableException
58      */
wipeDevice()59     public void wipeDevice() throws DeviceNotAvailableException {
60         // Make sure to keep the local.prop file for testing purposes.
61         File prop = mDevice.pullFile("/data/local.prop");
62         mDevice.rebootIntoBootloader();
63         mDevice.fastbootWipePartition(USERDATA_PARTITION);
64         mDevice.rebootUntilOnline();
65         if (prop != null) {
66             mDevice.pushFile(prop, "/data/local.prop");
67             mDevice.executeShellCommand("chmod 644 /data/local.prop");
68             mDevice.reboot();
69         }
70     }
71 
72     /**
73      * Remove a system app.
74      *
75      * @param systemApp {@link String} name for the application in the /system/app folder
76      * @param reboot set to <code>true</code> to optionally reboot device after app removal
77      * @throws DeviceNotAvailableException
78      */
removeSystemApp(String systemApp, boolean reboot)79     public void removeSystemApp(String systemApp, boolean reboot)
80             throws DeviceNotAvailableException {
81         mDevice.remountSystemWritable();
82         String cmd = String.format("rm %s", systemApp);
83         mDevice.executeShellCommand(cmd);
84         if (reboot) {
85             mDevice.reboot();
86         }
87         mDevice.waitForDeviceAvailable();
88     }
89 
90     /**
91      * Remove a system app and wipe the device.
92      *
93      * @param systemApp {@link String} name for the application in the /system/app folder
94      * @throws DeviceNotAvailableException
95      */
removeAndWipe(String systemApp)96     public void removeAndWipe(String systemApp) throws DeviceNotAvailableException {
97         removeSystemApp(systemApp, false);
98         wipeDevice();
99     }
100 
101     /**
102      * Expect that a given xpath exists in a given xml file.
103      *
104      * @param xmlFile {@link File} xml file to process
105      * @param xPathString {@link String} Xpath to look for
106      * @return true if the xpath is found
107      */
expectExists(File xmlFile, String xPathString)108     public boolean expectExists(File xmlFile, String xPathString) {
109         Node n = getNodeForXPath(xmlFile, xPathString);
110         if (n != null) {
111             CLog.d("Found node %s for xpath %s", n.getNodeName(), xPathString);
112             return true;
113         }
114         return false;
115     }
116 
117     /**
118      * Expect that the value of a given xpath starts with a given string.
119      *
120      * @param xmlFile {@link File} the xml file in question
121      * @param xPathString {@link String} the xpath to look for
122      * @param value {@link String} the expected start string of the xpath
123      * @return true if the value for the xpath starts with value, false otherwise
124      */
expectStartsWith(File xmlFile, String xPathString, String value)125     public boolean expectStartsWith(File xmlFile, String xPathString, String value) {
126         Node n = getNodeForXPath(xmlFile, xPathString);
127         if (n == null) {
128             CLog.d("Failed to find node for xpath %s", xPathString);
129             return false;
130         }
131         CLog.d("Value of node %s: %s", xPathString, n.getNodeValue());
132         return n.getNodeValue().toLowerCase().startsWith(value.toLowerCase());
133     }
134 
135     /**
136      * Expect that the value of a given xpath matches.
137      *
138      * @param xmlFile {@link File} the xml file in question
139      * @param xPathString {@link String} the xpath to look for
140      * @param value {@link String} the expected string value
141      * @return true if the value for the xpath matches, false otherwise
142      */
expectEquals(File xmlFile, String xPathString, String value)143     public boolean expectEquals(File xmlFile, String xPathString, String value) {
144         Node n = getNodeForXPath(xmlFile, xPathString);
145         if (n == null) {
146             CLog.d("Failed to find node for xpath %s", xPathString);
147             return false;
148         }
149         boolean result = n.getNodeValue().equalsIgnoreCase(value);
150         if (!result) {
151             CLog.v(
152                     "Value of node %s: \"%s\", expected: \"%s\"",
153                     xPathString, n.getNodeValue(), value);
154         }
155         return result;
156     }
157 
getNodeForXPath(File xmlFile, String xPathString)158     public Node getNodeForXPath(File xmlFile, String xPathString) {
159         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
160         try {
161             DocumentBuilder documentBuilder = factory.newDocumentBuilder();
162             Document doc = documentBuilder.parse(xmlFile);
163             XPathFactory xpFactory = XPathFactory.newInstance();
164             XPath xpath = xpFactory.newXPath();
165             XPathExpression expr = xpath.compile(xPathString);
166             Node node = (Node) expr.evaluate(doc, XPathConstants.NODE);
167             return node;
168         } catch (Exception e) {
169             CLog.e(e);
170         }
171         return null;
172     }
173 
174     /**
175      * Check if a given package has the said permission.
176      *
177      * @param packageName {@link String} the package in question
178      * @param permission {@link String} the permission to look for
179      * @return true if the permission exists, false otherwise
180      * @throws DeviceNotAvailableException
181      */
packageHasPermission(String packageName, String permission)182     public boolean packageHasPermission(String packageName, String permission)
183             throws DeviceNotAvailableException {
184         String cmd = "dumpsys package " + packageName;
185         String res = mDevice.executeShellCommand(cmd);
186         if (res != null) {
187             if (res.contains("grantedPermissions:")) {
188                 return res.contains(permission);
189             } else {
190                 Pattern perm =
191                         Pattern.compile(
192                                 String.format("^.*%s.*granted=true.*$", permission),
193                                 Pattern.MULTILINE);
194                 Matcher m = perm.matcher(res);
195                 return m.find();
196             }
197         }
198         CLog.d("Failed to execute shell command: %s", cmd);
199         return false;
200     }
201 
202     /**
203      * Check if a given package has the said permission.
204      *
205      * @param packageName {@link String} the package in question
206      * @param flag {@link String} the permission to look for
207      * @return true if the permission exists, false otherwise
208      * @throws DeviceNotAvailableException
209      */
packageHasFlag(String packageName, String flag)210     public boolean packageHasFlag(String packageName, String flag)
211             throws DeviceNotAvailableException {
212         String cmd = "dumpsys package " + packageName;
213         String res = mDevice.executeShellCommand(cmd);
214         if (res != null) {
215             Pattern flags = Pattern.compile("^.*flags=\\[(.*?)\\]$", Pattern.MULTILINE);
216             Matcher m = flags.matcher(res);
217             if (m.find()) {
218                 return m.group(1).contains(flag);
219             } else {
220                 CLog.d("Failed to find package flags record in dumpsys package output");
221             }
222         }
223         CLog.d("Failed to execute shell command: %s", cmd);
224         return false;
225     }
226 
227     /**
228      * Helper method to install a file
229      *
230      * @param localFile the {@link File} to install
231      * @param replace set to <code>true</code> if re-install of app should be performed
232      * @param extraArgs optional extra arguments to pass. See 'adb shell pm install --help' for
233      *     available options.
234      * @throws DeviceNotAvailableException
235      */
installFile(final File localFile, final boolean replace, String... extraArgs)236     public void installFile(final File localFile, final boolean replace, String... extraArgs)
237             throws DeviceNotAvailableException {
238         String result = mDevice.installPackage(localFile, replace, extraArgs);
239         Assert.assertNull(
240                 String.format(
241                         "Failed to install file %s with result %s",
242                         localFile.getAbsolutePath(), result),
243                 result);
244     }
245 
246     /**
247      * Helper method to stop system shell.
248      *
249      * @throws DeviceNotAvailableException
250      */
stopSystem()251     public void stopSystem() throws DeviceNotAvailableException {
252         mDevice.executeShellCommand("stop");
253     }
254 
255     /**
256      * Helper method to start system shell. It also reset the flag dev.bootcomplete to 0 to ensure
257      * that the package manager had a chance to finish.
258      *
259      * @throws DeviceNotAvailableException
260      */
startSystem()261     public void startSystem() throws DeviceNotAvailableException {
262         mDevice.executeShellCommand("setprop dev.bootcomplete 0");
263         mDevice.executeShellCommand("start");
264         mDevice.waitForDeviceAvailable();
265     }
266 
267     /**
268      * Convenience method to stop, then start the runtime.
269      *
270      * @throws DeviceNotAvailableException
271      */
restartSystem()272     public void restartSystem() throws DeviceNotAvailableException {
273         stopSystem();
274         startSystem();
275     }
276 
277     /**
278      * Push apk to system app directory on the device.
279      *
280      * @param localFile {@link File} the local file to install
281      * @param deviceFilePath {@link String} the remote device path where to install the application
282      * @throws DeviceNotAvailableException
283      */
pushSystemApp(final File localFile, final String deviceFilePath)284     public void pushSystemApp(final File localFile, final String deviceFilePath)
285             throws DeviceNotAvailableException {
286         mDevice.remountSystemWritable();
287         stopSystem();
288         mDevice.pushFile(localFile, deviceFilePath);
289         startSystem();
290     }
291 
292     /**
293      * Pulls packages xml file from the device.
294      *
295      * @return {@link File} xml file for all packages on device.
296      * @throws DeviceNotAvailableException
297      */
pullPackagesXML()298     public File pullPackagesXML() throws DeviceNotAvailableException {
299         return mDevice.pullFile(PACKAGE_XML_FILE);
300     }
301 }
302