1 /* 2 * Copyright (C) 2011 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.ddmlib.Log; 20 import com.android.tradefed.build.IDeviceBuildInfo; 21 import com.android.tradefed.device.DeviceNotAvailableException; 22 import com.android.tradefed.device.ITestDevice; 23 import com.android.tradefed.util.FileUtil; 24 import com.android.tradefed.util.IRunUtil; 25 import com.android.tradefed.util.RunUtil; 26 import com.android.tradefed.util.ZipUtil2; 27 28 import org.apache.commons.compress.archivers.zip.ZipFile; 29 30 import java.io.File; 31 import java.io.IOException; 32 33 /** 34 * A class that flashes an image on a physical Android device with a CDMA radio. 35 * <p /> 36 * This class is required because a special flashing sequence is needed to properly update the 37 * radio baseband, since it is typically the case that the radio and bootloader can't communicate 38 * directly. Typically, they use the RIL (which runs in userspace) as a proxy. 39 */ 40 public class CdmaDeviceFlasher extends FastbootDeviceFlasher { 41 private static final String LOG_TAG = "CdmaDeviceFlasher"; 42 43 private boolean mShouldFlashBaseband = false; 44 45 /** Time to allow for baseband to flash (in recovery mode), in ms */ 46 protected static final int BASEBAND_FLASH_TIMEOUT = 10*60*1000; 47 48 /** 49 * {@inheritDoc} 50 */ 51 @Override getBootPartitionName()52 protected String getBootPartitionName() { 53 return "bootloader"; 54 } 55 56 /** 57 * {@inheritDoc} 58 * <p /> 59 * If the baseband is up-to-date, this flasher behaves identically to the DeviceFlasher 60 * superclass. If the baseband needs to be updated, it does the following: 61 * <ol> 62 * <li>Flash the bootloader as normal</li> 63 * <li>Unpack the updater.zip</li> 64 * <li>Flash the new baseband, but <emph>don't reboot afterward</emph></li> 65 * <li>Flash the boot, recovery, and system partitions</li> 66 * <li>Reboot (device comes up in Recovery to actually flash baseband)</li> 67 * <li>Reboot again</li> 68 * <li>Flash userdata</li> 69 * <li>Reboot into userspace</li> 70 * </ol> 71 */ 72 @Override flash(ITestDevice device, IDeviceBuildInfo deviceBuild)73 public void flash(ITestDevice device, IDeviceBuildInfo deviceBuild) throws TargetSetupError, 74 DeviceNotAvailableException { 75 76 Log.i(LOG_TAG, String.format("Flashing device %s with build %s", 77 device.getSerialNumber(), deviceBuild.getBuildId())); 78 79 // get system build id and build flavor before booting into fastboot 80 String systemBuildId = device.getBuildId(); 81 String systemBuildFlavor = device.getBuildFlavor(); 82 83 device.rebootIntoBootloader(); 84 85 downloadFlashingResources(device, deviceBuild); 86 87 checkAndFlashBootloader(device, deviceBuild); 88 if (checkShouldFlashBaseband(device, deviceBuild)) { 89 Log.i(LOG_TAG, "Performing special CDMA baseband update flash procedure"); 90 // We need to flash these partitions: userdata, system, boot, radio, recovery 91 // Flash userdata. system, boot, radio, recovery remain 92 flashUserData(device, deviceBuild); 93 wipeCache(device); 94 95 // Flash baseband. system, boot, recovery remain 96 mShouldFlashBaseband = true; 97 checkAndFlashBaseband(device, deviceBuild); 98 99 // Flash system, boot, recovery. Will reboot the device before returning. After these 100 // are flashed, all partitions are up-to-date. 101 checkAndFlashSystem(device, systemBuildId, systemBuildFlavor, deviceBuild); 102 // flashSystem will leave the device in fastboot; reboot into userspace 103 device.reboot(); 104 } else { 105 // Do the standard thing 106 flashUserData(device, deviceBuild); 107 wipeCache(device); 108 checkAndFlashSystem(device, systemBuildId, systemBuildFlavor, deviceBuild); 109 device.reboot(); 110 } 111 } 112 113 /** 114 * Flashes the given baseband image and <emph>does not reboot the device afterward</emph>. 115 * 116 * @param device the {@link ITestDevice} to flash 117 * @param basebandImageFile the baseband image {@link File} 118 * @throws DeviceNotAvailableException if device is not available 119 * @throws TargetSetupError if failed to flash baseband 120 */ 121 @Override flashBaseband(ITestDevice device, File basebandImageFile)122 protected void flashBaseband(ITestDevice device, File basebandImageFile) 123 throws DeviceNotAvailableException, TargetSetupError { 124 executeLongFastbootCmd(device, "flash", BASEBAND_IMAGE_NAME, 125 basebandImageFile.getAbsolutePath()); 126 } 127 128 /** 129 * Flash an individual partition 130 */ flashNamedPartition(ITestDevice device, File dir, String partition)131 private void flashNamedPartition(ITestDevice device, File dir, String partition) 132 throws DeviceNotAvailableException, TargetSetupError { 133 File imgFile = new File(dir, partition + ".img"); 134 flashPartition(device, imgFile, partition); 135 } 136 137 /** 138 * Extract the updater zip to a directory and return the path of that directory 139 * <p /> 140 * Exposed for unit testing 141 */ extractSystemZip(IDeviceBuildInfo deviceBuild)142 protected File extractSystemZip(IDeviceBuildInfo deviceBuild) throws IOException { 143 File updateDir = FileUtil.createTempDir(LOG_TAG); 144 ZipFile updater = new ZipFile(deviceBuild.getDeviceImageFile().getAbsolutePath()); 145 ZipUtil2.extractZip(updater, updateDir); 146 return updateDir; 147 } 148 149 /** 150 * {@inheritDoc} 151 */ 152 @Override flashSystem(ITestDevice device, IDeviceBuildInfo deviceBuild)153 protected void flashSystem(ITestDevice device, IDeviceBuildInfo deviceBuild) 154 throws DeviceNotAvailableException, TargetSetupError { 155 if (mShouldFlashBaseband) { 156 // Unpack updater zip and flash partitions manually 157 Log.i(LOG_TAG, String.format("MANUALLY flashing individual partitions on %s.", 158 device.getSerialNumber())); 159 File updateDir = null; 160 try { 161 // unzip 162 updateDir = extractSystemZip(deviceBuild); 163 164 // Expect updateDir to contain boot.img, recovery.img, system.img 165 flashNamedPartition(device, updateDir, "boot"); 166 flashNamedPartition(device, updateDir, "recovery"); 167 flashNamedPartition(device, updateDir, "system"); 168 } catch (IOException e) { 169 throw new TargetSetupError(String.format("Got IOException: %s", e.getMessage()), 170 device.getDeviceDescriptor()); 171 } finally { 172 if (updateDir != null) { 173 FileUtil.recursiveDelete(updateDir); 174 updateDir = null; 175 } 176 } 177 178 // Do the fancy double-reboot 179 // Don't use device.reboot() the first time because radio flash can take 5+ minutes 180 device.executeFastbootCommand("reboot"); 181 device.waitForDeviceOnline(BASEBAND_FLASH_TIMEOUT); 182 device.waitForDeviceAvailable(); 183 // Wait for radio version updater to do its thing 184 getRunUtil().sleep(5000); 185 // Reboot again. 186 device.reboot(); 187 // Wait for radio version updater to do its thing again 188 getRunUtil().sleep(5000); 189 // Hopefully, that should be it 190 device.rebootIntoBootloader(); 191 192 } else { 193 super.flashSystem(device, deviceBuild); 194 device.waitForDeviceOnline(); 195 device.rebootIntoBootloader(); 196 } 197 } 198 199 /** 200 * Get the {@link RunUtil} instance to use. 201 * <p/> 202 * Exposed for unit testing. 203 */ 204 @Override getRunUtil()205 protected IRunUtil getRunUtil() { 206 return RunUtil.getDefault(); 207 } 208 } 209