blob: 4062d210dc7ca4df0fe388ab30d9a8247d35c8d8 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tradefed.targetprep;
import com.android.ddmlib.Log;
import com.android.tradefed.build.IDeviceBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.util.FileUtil;
import com.android.tradefed.util.IRunUtil;
import com.android.tradefed.util.RunUtil;
import java.io.File;
import java.io.IOException;
import java.util.zip.ZipFile;
/**
* A class that flashes an image on a physical Android device with a CDMA radio.
* <p />
* This class is required because a special flashing sequence is needed to properly update the
* radio baseband, since it is typically the case that the radio and bootloader can't communicate
* directly. Typically, they use the RIL (which runs in userspace) as a proxy.
*/
public class CdmaDeviceFlasher extends FastbootDeviceFlasher {
private static final String LOG_TAG = "CdmaDeviceFlasher";
private boolean mShouldFlashBaseband = false;
/** Time to allow for baseband to flash (in recovery mode), in ms */
protected static final int BASEBAND_FLASH_TIMEOUT = 1000*60*10;
/**
* {@inheritDoc}
*/
@Override
protected String getBootPartitionName() {
return "bootloader";
}
/**
* {@inheritDoc}
* <p />
* If the baseband is up-to-date, this flasher behaves identically to the DeviceFlasher
* superclass. If the baseband needs to be updated, it does the following:
* <ol>
* <li>Flash the bootloader as normal</li>
* <li>Unpack the updater.zip</li>
* <li>Flash the new baseband, but <emph>don't reboot afterward</emph></li>
* <li>Flash the boot, recovery, and system partitions</li>
* <li>Reboot (device comes up in Recovery to actually flash baseband)</li>
* <li>Reboot again</li>
* <li>Flash userdata</li>
* <li>Reboot into userspace</li>
* </ol>
*/
@Override
public void flash(ITestDevice device, IDeviceBuildInfo deviceBuild) throws TargetSetupError,
DeviceNotAvailableException {
Log.i(LOG_TAG, String.format("Flashing device %s with build %s",
device.getSerialNumber(), deviceBuild.getBuildId()));
// get system build id before booting into fastboot
String systemBuildId = device.getBuildId();
device.rebootIntoBootloader();
downloadFlashingResources(device, deviceBuild);
checkAndFlashBootloader(device, deviceBuild);
if (checkShouldFlashBaseband(device, deviceBuild)) {
Log.i(LOG_TAG, "Performing special CDMA baseband update flash procedure");
// Flash baseband; userdata and system are out-of-date now
mShouldFlashBaseband = true;
checkAndFlashBaseband(device, deviceBuild);
// Flash userdata and erase cache; system is out-of-date now
flashUserData(device, deviceBuild);
eraseCache(device);
// Flash system, which will cause a reboot. After system is flashed, all partitions are
// up-to-date
checkAndFlashSystem(device, systemBuildId, deviceBuild);
// flashSystem will leave the device in fastboot; reboot into userspace
device.reboot();
} else {
// Do the standard thing
flashUserData(device, deviceBuild);
eraseCache(device);
checkAndFlashSystem(device, systemBuildId, deviceBuild);
}
}
/**
* Flashes the given baseband image and <emph>does not reboot the device afterward</emph>.
*
* @param device the {@link ITestDevice} to flash
* @param basebandImageFile the baseband image {@link File}
* @throws DeviceNotAvailableException if device is not available
* @throws TargetSetupError if failed to flash baseband
*/
@Override
protected void flashBaseband(ITestDevice device, File basebandImageFile)
throws DeviceNotAvailableException, TargetSetupError {
executeLongFastbootCmd(device, "flash", BASEBAND_IMAGE_NAME,
basebandImageFile.getAbsolutePath());
}
/**
* Flash an individual partition
*/
private void flashNamedPartition(ITestDevice device, File dir, String partition)
throws DeviceNotAvailableException, TargetSetupError {
File imgFile = new File(dir, partition + ".img");
flashPartition(device, imgFile, partition);
}
/**
* Extract the updater zip to a directory and return the path of that directory
* <p />
* Exposed for unit testing
*/
protected File extractSystemZip(IDeviceBuildInfo deviceBuild) throws IOException {
File updateDir = FileUtil.createTempDir(LOG_TAG);
ZipFile updater = new ZipFile(deviceBuild.getDeviceImageFile().getAbsolutePath());
FileUtil.extractZip(updater, updateDir);
return updateDir;
}
/**
* {@inheritDoc}
*/
@Override
protected void flashSystem(ITestDevice device, IDeviceBuildInfo deviceBuild)
throws DeviceNotAvailableException, TargetSetupError {
if (mShouldFlashBaseband) {
// Unpack updater zip and flash partitions manually
Log.i(LOG_TAG, String.format("MANUALLY flashing individual partitions on %s.",
device.getSerialNumber()));
File updateDir = null;
try {
// unzip
updateDir = extractSystemZip(deviceBuild);
// Expect updateDir to contain boot.img, recovery.img, system.img
flashNamedPartition(device, updateDir, "boot");
flashNamedPartition(device, updateDir, "recovery");
flashNamedPartition(device, updateDir, "system");
} catch (IOException e) {
throw new TargetSetupError(String.format("Got IOException: %s", e.getMessage()));
} finally {
if (updateDir != null) {
FileUtil.recursiveDelete(updateDir);
updateDir = null;
}
}
// Do the fancy double-reboot
// Don't use device.reboot() the first time because radio flash can take 5+ minutes
device.executeFastbootCommand("reboot");
device.waitForDeviceOnline(BASEBAND_FLASH_TIMEOUT);
device.waitForDeviceAvailable();
// Wait for radio version updater to do its thing
getRunUtil().sleep(5000);
// Reboot again.
device.reboot();
// Wait for radio version updater to do its thing again
getRunUtil().sleep(5000);
// Hopefully, that should be it
device.rebootIntoBootloader();
} else {
super.flashSystem(device, deviceBuild);
}
}
/**
* Get the {@link RunUtil} instance to use.
* <p/>
* Exposed for unit testing.
*/
protected IRunUtil getRunUtil() {
return RunUtil.getDefault();
}
}