• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.tradefed.targetprep;
17 
18 import com.android.tradefed.build.IBuildInfo;
19 import com.android.tradefed.config.Option;
20 import com.android.tradefed.config.OptionClass;
21 import com.android.tradefed.device.DeviceNotAvailableException;
22 import com.android.tradefed.device.ITestDevice;
23 import com.android.tradefed.log.LogUtil.CLog;
24 import com.android.tradefed.util.CommandResult;
25 import com.android.tradefed.util.CommandStatus;
26 import com.android.tradefed.util.IRunUtil;
27 import com.android.tradefed.util.RunUtil;
28 
29 import com.google.common.annotations.VisibleForTesting;
30 
31 import java.io.File;
32 
33 /**
34  * A {@link ITargetPreparer} that replaces the preloaded classes file on a device.
35  *
36  * <p>Note that this preparer requires a rooted, debug build to work.
37  */
38 @OptionClass(alias = "preloaded-classes-preparer")
39 public class PreloadedClassesPreparer extends BaseTargetPreparer {
40     // Preload tool commands
41     private static final String TOOL_CMD = "java -cp %s com.android.preload.Main --seq %s %s";
42     private static final String WRITE_CMD = "write %s";
43     // Defaults
44     public static final long DEFAULT_TIMEOUT_MS = 5 * 60 * 1000;
45 
46     @Option(
47         name = "preload-file",
48         description = "The new preloaded classes file to put on the device."
49     )
50     private File mNewClassesFile = null;
51 
52     @Option(name = "preload-tool", description = "Overridden location of the preload tool JAR.")
53     private String mPreloadToolJarPath = "";
54 
55     @Option(name = "skip", description = "Skip this preparer entirely.")
56     private boolean mSkip = false;
57 
58     @Option(
59         name = "write-timeout",
60         isTimeVal = true,
61         description = "Maximum timeout for overwriting the file in milliseconds."
62     )
63     private long mWriteTimeout = DEFAULT_TIMEOUT_MS;
64 
65     /** {@inheritDoc} */
66     @Override
setUp(ITestDevice device, IBuildInfo buildInfo)67     public void setUp(ITestDevice device, IBuildInfo buildInfo)
68             throws TargetSetupError, BuildError, DeviceNotAvailableException {
69         if (mSkip) {
70             return;
71         } else if (getPreloadedClassesPath().isEmpty()) {
72             CLog.w("No preloaded classes file specified. Skipping preparer.");
73             return;
74         }
75 
76         // Download preload tool, if not supplied
77         if (getPreloadToolPath().isEmpty()) {
78             File preload = buildInfo.getFile("preload2.jar");
79             if (preload != null && preload.exists()) {
80                 setPreloadToolPath(preload.getAbsolutePath());
81             } else {
82                 throw new TargetSetupError(
83                         "Unable to find the preload tool.", device.getDeviceDescriptor());
84             }
85         }
86 
87         // Root, disable verity, and remount
88         device.enableAdbRoot();
89         device.remountSystemWritable();
90         // Root again after rebooting
91         device.enableAdbRoot();
92         // Construct the command
93         String exportCmd = String.format(WRITE_CMD, getPreloadedClassesPath());
94         String[] fullCmd =
95                 String.format(TOOL_CMD, getPreloadToolPath(), device.getSerialNumber(), exportCmd)
96                         .split(" ");
97         CommandResult result = getRunUtil().runTimedCmd(mWriteTimeout, fullCmd);
98         if (!CommandStatus.SUCCESS.equals(result.getStatus())) {
99             throw new TargetSetupError(
100                     String.format("Error writing: %s", result.getStderr()),
101                     device.getDeviceDescriptor());
102         }
103         // Wait for the device to be reconnected
104         device.waitForDeviceAvailable();
105     }
106 
107     /**
108      * Get the {@link IRunUtil} instance to use.
109      *
110      * <p>Exposed so unit tests can mock.
111      */
112     @VisibleForTesting
getRunUtil()113     protected IRunUtil getRunUtil() {
114         return RunUtil.getDefault();
115     }
116 
117     /**
118      * Get the preloaded classes file.
119      *
120      * <p>Exposed so unit tests can mock.
121      */
122     @VisibleForTesting
getPreloadedClassesPath()123     protected String getPreloadedClassesPath() {
124         return (mNewClassesFile != null) ? mNewClassesFile.getAbsolutePath() : "";
125     }
126 
127     /** Get the preload tool path. */
getPreloadToolPath()128     protected String getPreloadToolPath() {
129         return mPreloadToolJarPath;
130     }
131 
132     /** Set the preload tool path. */
setPreloadToolPath(String path)133     protected void setPreloadToolPath(String path) {
134         mPreloadToolJarPath = path;
135     }
136 }
137