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 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 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 123 protected String getPreloadedClassesPath() { 124 return (mNewClassesFile != null) ? mNewClassesFile.getAbsolutePath() : ""; 125 } 126 127 /** Get the preload tool path. */ 128 protected String getPreloadToolPath() { 129 return mPreloadToolJarPath; 130 } 131 132 /** Set the preload tool path. */ 133 protected void setPreloadToolPath(String path) { 134 mPreloadToolJarPath = path; 135 } 136 } 137