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