Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
      5  * in compliance with the License. You may obtain a copy of the License at
      6  *
      7  * http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software distributed under the License
     10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
     11  * or implied. See the License for the specific language governing permissions and limitations under
     12  * the License.
     13  */
     14 
     15 package android.jvmti.cts;
     16 
     17 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
     18 import com.android.ddmlib.NullOutputReceiver;
     19 import com.android.tradefed.build.IBuildInfo;
     20 import com.android.tradefed.config.Option;
     21 import com.android.tradefed.device.ITestDevice;
     22 import com.android.tradefed.log.LogUtil.CLog;
     23 import com.android.tradefed.testtype.DeviceTestCase;
     24 import com.android.tradefed.testtype.IAbi;
     25 import com.android.tradefed.testtype.IAbiReceiver;
     26 import com.android.tradefed.testtype.IBuildReceiver;
     27 import com.android.tradefed.util.AbiUtils;
     28 import com.android.tradefed.util.FileUtil;
     29 import com.android.tradefed.util.ZipUtil;
     30 
     31 import java.io.File;
     32 import java.util.concurrent.TimeUnit;
     33 import java.util.zip.ZipFile;
     34 
     35 /**
     36  * Specialization of JvmtiHostTest to test attaching on startup.
     37  */
     38 public class JvmtiAttachingHostTest extends DeviceTestCase implements IBuildReceiver, IAbiReceiver {
     39     // inject these options from HostTest directly using --set-option <option name>:<option value>
     40     @Option(name = "package-name",
     41             description = "The package name of the device test",
     42             mandatory = true)
     43     private String mTestPackageName = null;
     44 
     45     @Option(name = "test-file-name",
     46             description = "the name of a test zip file to install on device.",
     47             mandatory = true)
     48     private String mTestApk = null;
     49 
     50     private CompatibilityBuildHelper mBuildHelper;
     51     private IAbi mAbi;
     52     private int mCurrentUser;
     53 
     54     @Override
     55     public void setBuild(IBuildInfo arg0) {
     56         mBuildHelper = new CompatibilityBuildHelper(arg0);
     57     }
     58 
     59     @Override
     60     public void setAbi(IAbi arg0) {
     61         mAbi = arg0;
     62     }
     63 
     64     private static interface TestRun {
     65         public void run(ITestDevice device, String pkg, String apk, String abiName);
     66     }
     67 
     68     private final static String AGENT = "libctsjvmtiattachagent.so";
     69 
     70     @Override
     71     protected void setUp() throws Exception {
     72         mCurrentUser = getDevice().getCurrentUser();
     73     }
     74 
     75     public void testJvmtiAttachDuringBind() throws Exception {
     76         runJvmtiAgentLoadTest((ITestDevice device, String pkg, String apk, String abiName) -> {
     77             try {
     78                 runAttachTestCmd(device, pkg, "--attach-agent-bind " + AGENT);
     79             } catch (Exception e) {
     80                 throw new RuntimeException("Failed bind-time attaching", e);
     81             }
     82         });
     83     }
     84 
     85     public void testJvmtiAttachEarly() throws Exception {
     86         runJvmtiAgentLoadTest((ITestDevice device, String pkg, String apk, String abiName) -> {
     87             try {
     88                 String pwd = device.executeShellCommand(
     89                         "run-as " + pkg + " --user " + mCurrentUser + " pwd");
     90                 if (pwd == null) {
     91                     throw new RuntimeException("pwd failed");
     92                 }
     93                 pwd = pwd.trim();
     94                 if (pwd.isEmpty()) {
     95                     throw new RuntimeException("pwd failed");
     96                 }
     97 
     98                 // Give it a different name, so we do not have "contamination" from
     99                 // the test APK.
    100                 String libInDataData = AGENT.substring(0, AGENT.length() - ".so".length())
    101                         + "2.so";
    102                 String agentInDataData =
    103                         installLibToDataData(device, pkg, abiName, apk, pwd, AGENT,
    104                                 libInDataData);
    105                 runAttachTestCmd(device, pkg, "--attach-agent " + agentInDataData);
    106             } catch (Exception e) {
    107                 throw new RuntimeException("Failed pre-bind attaching", e);
    108             }
    109         });
    110     }
    111 
    112     public void testJvmtiAgentAppInternal() throws Exception {
    113         runJvmtiAgentLoadTest((ITestDevice device, String pkg, String apk, String abiName) -> {
    114             try {
    115                 String setAgentAppCmd = "cmd activity set-agent-app " + pkg + " " + AGENT;
    116                 device.executeShellCommand(setAgentAppCmd);
    117             } catch (Exception e) {
    118                 throw new RuntimeException("Failed running set-agent-app", e);
    119             }
    120 
    121             try {
    122                 runAttachTestCmd(device, pkg, "");
    123 
    124                 // And again.
    125                 runAttachTestCmd(device, pkg, "");
    126             } catch (Exception e) {
    127                 throw new RuntimeException("Failed agent-app attaching", e);
    128             }
    129         });
    130     }
    131 
    132     public void testJvmtiAgentAppExternal() throws Exception {
    133         runJvmtiAgentLoadTest((ITestDevice device, String pkg, String apk, String abiName) -> {
    134             try {
    135                 String pwd = device.executeShellCommand(
    136                         "run-as " + pkg + " --user " + mCurrentUser + " pwd");
    137                 if (pwd == null) {
    138                     throw new RuntimeException("pwd failed");
    139                 }
    140                 pwd = pwd.trim();
    141                 if (pwd.isEmpty()) {
    142                     throw new RuntimeException("pwd failed");
    143                 }
    144 
    145                 // Give it a different name, so we do not have "contamination" from
    146                 // the test APK.
    147                 String libInDataData = AGENT.substring(0, AGENT.length() - ".so".length())
    148                         + "2.so";
    149                 String agentInDataData =
    150                         installLibToDataData(device, pkg, abiName, apk, pwd, AGENT,
    151                                 libInDataData);
    152 
    153                 String setAgentAppCmd = "cmd activity set-agent-app " + pkg + " " + agentInDataData;
    154                 device.executeShellCommand(setAgentAppCmd);
    155             } catch (Exception e) {
    156                 throw new RuntimeException("Failed running set-agent-app", e);
    157             }
    158 
    159             try {
    160                 runAttachTestCmd(device, pkg, "");
    161 
    162                 // And again.
    163                 runAttachTestCmd(device, pkg, "");
    164             } catch (Exception e) {
    165                 throw new RuntimeException("Failed agent-app attaching", e);
    166             }
    167         });
    168     }
    169 
    170     private void runJvmtiAgentLoadTest(TestRun runner) throws Exception {
    171         final ITestDevice device = getDevice();
    172 
    173         String testingArch = AbiUtils.getBaseArchForAbi(mAbi.getName());
    174         String deviceArch = getDeviceBaseArch(device);
    175 
    176         //Only bypass if Base Archs are different
    177         if (!testingArch.equals(deviceArch)) {
    178             CLog.d(
    179                     "Bypass as testing Base Arch:"
    180                             + testingArch
    181                             + " is different from DUT Base Arch:"
    182                             + deviceArch);
    183             return;
    184         }
    185 
    186         if (mTestApk == null || mTestPackageName == null) {
    187             throw new IllegalStateException("Incorrect configuration");
    188         }
    189 
    190         // Wakeup the device if it is on the lockscreen and move it to the home screen.
    191         device.executeShellCommand("input keyevent KEYCODE_WAKEUP");
    192         device.executeShellCommand("wm dismiss-keyguard");
    193         device.executeShellCommand("input keyevent KEYCODE_HOME");
    194 
    195         runner.run(device, mTestPackageName, mTestApk, mAbi.getName());
    196     }
    197 
    198     private String getDeviceBaseArch(ITestDevice device) throws Exception {
    199         String abi = device.executeShellCommand("getprop ro.product.cpu.abi").replace("\n", "");
    200         CLog.d("DUT abi:" + abi);
    201         return AbiUtils.getBaseArchForAbi(abi);
    202     }
    203 
    204     private static void runAttachTestCmd(ITestDevice device, String pkg, String agentParams)
    205             throws Exception {
    206         String attachCmd = "cmd activity start -S -W " + agentParams + " -n " + pkg
    207                 + "/android.jvmti.JvmtiActivity";
    208 
    209         // Don't try to parse the output. The test will time out anyways if this didn't
    210         // work.
    211         device.executeShellCommand(attachCmd, NullOutputReceiver.getReceiver(), 10,
    212                 TimeUnit.SECONDS, 1);
    213     }
    214 
    215     private String installLibToDataData(ITestDevice device, String pkg, String abiName,
    216             String apk, String dataData, String library, String newLibName) throws Exception {
    217         ZipFile zf = null;
    218         File tmpFile = null;
    219         String libInTmp = null;
    220         try {
    221             String libInDataData = dataData + "/" + newLibName;
    222 
    223             File apkFile = mBuildHelper.getTestFile(apk);
    224             zf = new ZipFile(apkFile);
    225 
    226             String libPathInApk = "lib/" + abiName + "/" + library;
    227             tmpFile = ZipUtil.extractFileFromZip(zf, libPathInApk);
    228 
    229             libInTmp = "/data/local/tmp/" + tmpFile.getName();
    230             if (!device.pushFile(tmpFile, libInTmp)) {
    231                 throw new RuntimeException("Could not push library " + library + " to device");
    232             }
    233 
    234             String runAsCp = device.executeShellCommand(
    235                     "run-as " + pkg + " --user " + mCurrentUser +
    236                             " cp " + libInTmp + " " + libInDataData);
    237             if (runAsCp != null && !runAsCp.trim().isEmpty()) {
    238                 throw new RuntimeException(runAsCp.trim());
    239             }
    240 
    241             String runAsChmod = device.executeShellCommand(
    242                     "run-as " + pkg + " --user " + mCurrentUser + " chmod a+x " + libInDataData);
    243             if (runAsChmod != null && !runAsChmod.trim().isEmpty()) {
    244                 throw new RuntimeException(runAsChmod.trim());
    245             }
    246 
    247             return libInDataData;
    248         } finally {
    249             FileUtil.deleteFile(tmpFile);
    250             ZipUtil.closeZip(zf);
    251             if (libInTmp != null) {
    252                 try {
    253                     device.executeShellCommand("rm " + libInTmp);
    254                 } catch (Exception e) {
    255                     CLog.e("Failed cleaning up library on device");
    256                 }
    257             }
    258         }
    259     }
    260 }
    261