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.tradefed.targetprep; 18 19 import com.android.tradefed.build.IBuildInfo; 20 import com.android.tradefed.build.KernelDeviceBuildInfo; 21 import com.android.tradefed.device.DeviceNotAvailableException; 22 import com.android.tradefed.device.DeviceUnresponsiveException; 23 import com.android.tradefed.device.ITestDevice; 24 import com.android.tradefed.log.LogUtil.CLog; 25 import com.android.tradefed.util.CommandResult; 26 import com.android.tradefed.util.CommandStatus; 27 import com.android.tradefed.util.FileUtil; 28 import com.android.tradefed.util.IRunUtil; 29 import com.android.tradefed.util.RunUtil; 30 31 import java.io.File; 32 import java.io.IOException; 33 34 /** 35 * A {@link ITargetPreparer} that flashes a kernel on the device. 36 */ 37 public class KernelFlashPreparer implements ITargetPreparer { 38 39 /** 40 * {@inheritDoc} 41 * <p> 42 * Expects a {@link KernelDeviceBuildInfo} that returns non-null values for 43 * {@link KernelDeviceBuildInfo#getMkbootimgFile()} and 44 * {@link KernelDeviceBuildInfo#getRamdiskFile()}. 45 * </p> 46 */ 47 @Override 48 public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError, 49 BuildError, DeviceNotAvailableException { 50 if (!(buildInfo instanceof KernelDeviceBuildInfo)) { 51 throw new IllegalArgumentException("Provided buildInfo is not a KernelDeviceBuildInfo"); 52 } 53 54 KernelDeviceBuildInfo kernelBuildInfo = (KernelDeviceBuildInfo) buildInfo; 55 CLog.i("Flashing device %s running %s with kernel %s", device.getSerialNumber(), 56 device.getBuildId(), kernelBuildInfo.getSha1()); 57 58 if (kernelBuildInfo.getRamdiskFile() == null) { 59 throw new TargetSetupError("Missing ramdisk file", device.getDeviceDescriptor()); 60 } 61 if (kernelBuildInfo.getMkbootimgFile() == null) { 62 throw new TargetSetupError("Missing mkbootimg file", device.getDeviceDescriptor()); 63 } 64 if (kernelBuildInfo.getKernelFile() == null) { 65 throw new TargetSetupError("Missing kernel file", device.getDeviceDescriptor()); 66 } 67 68 kernelBuildInfo.getMkbootimgFile().setExecutable(true); 69 70 File boot = null; 71 try { 72 boot = createBootImage(kernelBuildInfo.getMkbootimgFile(), 73 kernelBuildInfo.getKernelFile(), kernelBuildInfo.getRamdiskFile()); 74 } catch (IOException e) { 75 throw new TargetSetupError("Could not create boot image", e, 76 device.getDeviceDescriptor()); 77 } 78 79 try { 80 device.rebootIntoBootloader(); 81 CLog.d("fastboot flash boot %s", boot.getAbsolutePath()); 82 device.executeFastbootCommand("flash", "boot", boot.getAbsolutePath()); 83 } finally { 84 FileUtil.deleteFile(boot); 85 } 86 87 try { 88 device.reboot(); 89 } catch (DeviceUnresponsiveException e) { 90 // assume this is a build problem 91 throw new BuildError(String.format("Device %s did not become available after " + 92 "flashing kernel", device.getSerialNumber()), device.getDeviceDescriptor()); 93 } 94 device.postBootSetup(); 95 } 96 97 /** 98 * Creates a boot.img file using mkbootimg, ramdisk, and kernel files. 99 * <p> 100 * Runs {@code mkbootimg --kernel (filename) --ramdisk (filename) -o (filename)} to create a 101 * boot.img image file. Exposed for unit testing. 102 * </p> 103 * 104 * @param mkbootimg the mkbootimg executable 105 * @param kernel the kernel file 106 * @param ramdisk the ramdisk file 107 * @return a boot.img {@link File} for the build and kernel build 108 * @throws IOException if there was an exception making the boot image 109 */ 110 File createBootImage(File mkbootimg, File kernel, File ramdisk) throws IOException { 111 CLog.d("Create boot.img from %s and %s", kernel.getAbsolutePath(), 112 ramdisk.getAbsolutePath()); 113 String bootPath = getBootImgPath(); 114 try { 115 String[] cmd = {mkbootimg.getAbsolutePath(), "--kernel", kernel.getAbsolutePath(), 116 "--ramdisk", ramdisk.getAbsolutePath(), "-o", bootPath}; 117 CommandResult result = getRunUtil().runTimedCmd(30 * 1000, cmd); 118 if (result.getStatus() != CommandStatus.SUCCESS) { 119 CLog.e("mkbootimg failed. Command status was %s", result.getStatus()); 120 FileUtil.deleteFile(new File(bootPath)); 121 throw new IOException(); 122 } 123 } catch (IOException e) { 124 FileUtil.deleteFile(new File(bootPath)); 125 throw e; 126 } catch (RuntimeException e) { 127 FileUtil.deleteFile(new File(bootPath)); 128 throw e; 129 } 130 return new File(bootPath); 131 } 132 133 /** 134 * Get an {@link IRunUtil} instance. Exposed for unit testing. 135 */ 136 IRunUtil getRunUtil() { 137 return RunUtil.getDefault(); 138 } 139 140 /** 141 * Create a path for the boot image using {@link FileUtil#createTempFile(String, String)}. 142 * Exposed for unit testing. 143 */ 144 String getBootImgPath() throws IOException { 145 File bootImg = FileUtil.createTempFile("boot", ".img"); 146 String bootImgPath = bootImg.getAbsolutePath(); 147 FileUtil.deleteFile(bootImg); 148 return bootImgPath; 149 } 150 } 151