企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
当设备处于offline状态时,cts框架就要调用IDeviceRecovery接口类去做相应的恢复工作。 # 接口 ~~~ /* * Copyright (C) 2010 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.device; /** * Interface for recovering a device that has gone offline. */ public interface IDeviceRecovery { /** * Attempt to recover the given device that can no longer be communicated with. * <p/> * Method should block and only return when device is in requested state. * * @param monitor the {@link IDeviceStateMonitor} to use. * @param recoverUntilOnline if true, method should return as soon as device is online on adb. * If false, method should block until device is fully available for testing (ie * {@link IDeviceStateMonitor#waitForDeviceAvailable()} succeeds. * @throws DeviceNotAvailableException if device could not be recovered */ public void recoverDevice(IDeviceStateMonitor monitor, boolean recoverUntilOnline) throws DeviceNotAvailableException; /** * Attempt to recover the given unresponsive device in recovery mode. * * @param monitor the {@link IDeviceStateMonitor} to use. * @throws DeviceNotAvailableException if device could not be recovered */ public void recoverDeviceRecovery(IDeviceStateMonitor monitor) throws DeviceNotAvailableException; /** * Attempt to recover the given unresponsive device in bootloader mode. * * @param monitor the {@link IDeviceStateMonitor} to use. * @throws DeviceNotAvailableException if device could not be recovered */ public void recoverDeviceBootloader(IDeviceStateMonitor monitor) throws DeviceNotAvailableException; } ~~~ 该接口中要三个方法: recoverDevice:连接不再通信的设备 recoverDeviceRecovery:当手机处于[Recovery](http://www.anqu.com/lab_74/21078/)工程模式下,已经发送信息,但是没有反应,就需要调用该方法再次重连。 recoverDeviceBootloader:恢复没有反馈的设备,与上面不同的是当前设备处于[BootLoader](http://mobile.zol.com.cn/242/2424698_all.html)模式下。 # 实现类 cts模式的实现类为WaitDeviceRecovery: ~~~ /* * Copyright (C) 2010 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.device; import com.android.ddmlib.AdbCommandRejectedException; import com.android.ddmlib.IDevice; import com.android.ddmlib.Log; import com.android.ddmlib.TimeoutException; import com.android.tradefed.config.Option; import com.android.tradefed.log.LogUtil.CLog; import com.android.tradefed.util.IRunUtil; import com.android.tradefed.util.RunUtil; import java.io.IOException; /** * A simple implementation of a {@link IDeviceRecovery} that waits for device to be online and * respond to simple commands. */ public class WaitDeviceRecovery implements IDeviceRecovery { private static final String LOG_TAG = "WaitDeviceRecovery"; /** the time in ms to wait before beginning recovery attempts */ protected static final long INITIAL_PAUSE_TIME = 5 * 1000; /** * The number of attempts to check if device is in bootloader. * <p/> * Exposed for unit testing */ public static final int BOOTLOADER_POLL_ATTEMPTS = 3; // TODO: add a separate configurable timeout per operation @Option(name="device-wait-time", description="maximum time in ms to wait for a single device recovery command.") protected long mWaitTime = 4 * 60 * 1000; @Option(name="bootloader-wait-time", description="maximum time in ms to wait for device to be in fastboot.") protected long mBootloaderWaitTime = 30 * 1000; @Option(name="shell-wait-time", description="maximum time in ms to wait for device shell to be responsive.") protected long mShellWaitTime = 30 * 1000; @Option(name = "disable-unresponsive-reboot", description = "If this is set, we will not attempt to reboot an unresponsive device" + "that is in userspace. Note that this will have no effect if the device is in " + "fastboot or is expected to be in fastboot.") protected boolean mDisableUnresponsiveReboot = false; /** * Get the {@link RunUtil} instance to use. * <p/> * Exposed for unit testing. */ protected IRunUtil getRunUtil() { return RunUtil.getDefault(); } /** * Sets the maximum time in ms to wait for a single device recovery command. */ void setWaitTime(long waitTime) { mWaitTime = waitTime; } /** * {@inheritDoc} */ @Override public void recoverDevice(IDeviceStateMonitor monitor, boolean recoverUntilOnline) throws DeviceNotAvailableException { // device may have just gone offline // sleep a small amount to give ddms state a chance to settle // TODO - see if there is better way to handle this Log.i(LOG_TAG, String.format("Pausing for %d for %s to recover", INITIAL_PAUSE_TIME, monitor.getSerialNumber())); getRunUtil().sleep(INITIAL_PAUSE_TIME); // ensure bootloader state is updated monitor.waitForDeviceBootloaderStateUpdate(); if (monitor.getDeviceState().equals(TestDeviceState.FASTBOOT)) { Log.i(LOG_TAG, String.format( "Found device %s in fastboot but expected online. Rebooting...", monitor.getSerialNumber())); // TODO: retry if failed getRunUtil().runTimedCmd(20*1000, "fastboot", "-s", monitor.getSerialNumber(), "reboot"); } // wait for device online IDevice device = monitor.waitForDeviceOnline(); if (device == null) { handleDeviceNotAvailable(monitor, recoverUntilOnline); return; } // occasionally device is erroneously reported as online - double check that we can shell // into device if (!monitor.waitForDeviceShell(mShellWaitTime)) { // treat this as a not available device handleDeviceNotAvailable(monitor, recoverUntilOnline); return; } if (!recoverUntilOnline) { if (monitor.waitForDeviceAvailable(mWaitTime) == null) { // device is online but not responsive handleDeviceUnresponsive(device, monitor); } } } /** * Handle situation where device is online but unresponsive. * @param monitor * @throws DeviceNotAvailableException */ protected void handleDeviceUnresponsive(IDevice device, IDeviceStateMonitor monitor) throws DeviceNotAvailableException { if (!mDisableUnresponsiveReboot) { rebootDevice(device); } IDevice newdevice = monitor.waitForDeviceOnline(); if (newdevice == null) { handleDeviceNotAvailable(monitor, false); return; } if (monitor.waitForDeviceAvailable(mWaitTime) == null) { throw new DeviceUnresponsiveException(String.format( "Device %s is online but unresponsive", monitor.getSerialNumber())); } } /** * Handle situation where device is not available. * * @param monitor the {@link IDeviceStateMonitor} * @param recoverTillOnline if true this method should return if device is online, and not * check for responsiveness * @throws DeviceNotAvailableException */ protected void handleDeviceNotAvailable(IDeviceStateMonitor monitor, boolean recoverTillOnline) throws DeviceNotAvailableException { throw new DeviceNotAvailableException(String.format("Could not find device %s", monitor.getSerialNumber())); } /** * {@inheritDoc} */ @Override public void recoverDeviceBootloader(final IDeviceStateMonitor monitor) throws DeviceNotAvailableException { // device may have just gone offline // wait a small amount to give device state a chance to settle // TODO - see if there is better way to handle this Log.i(LOG_TAG, String.format("Pausing for %d for %s to recover", INITIAL_PAUSE_TIME, monitor.getSerialNumber())); getRunUtil().sleep(INITIAL_PAUSE_TIME); // poll and wait for device to return to valid state long pollTime = mBootloaderWaitTime / BOOTLOADER_POLL_ATTEMPTS; for (int i=0; i < BOOTLOADER_POLL_ATTEMPTS; i++) { if (monitor.waitForDeviceBootloader(pollTime)) { handleDeviceBootloaderUnresponsive(monitor); // passed above check, abort return; } else if (monitor.getDeviceState() == TestDeviceState.ONLINE) { handleDeviceOnlineExpectedBootloader(monitor); return; } } handleDeviceBootloaderNotAvailable(monitor); } /** * Handle condition where device is online, but should be in bootloader state. * <p/> * If this method * @param monitor * @throws DeviceNotAvailableException */ protected void handleDeviceOnlineExpectedBootloader(final IDeviceStateMonitor monitor) throws DeviceNotAvailableException { Log.i(LOG_TAG, String.format("Found device %s online but expected fastboot.", monitor.getSerialNumber())); // call waitForDeviceOnline to get handle to IDevice IDevice device = monitor.waitForDeviceOnline(); if (device == null) { handleDeviceBootloaderNotAvailable(monitor); return; } rebootDeviceIntoBootloader(device); if (!monitor.waitForDeviceBootloader(mBootloaderWaitTime)) { throw new DeviceNotAvailableException(String.format( "Device %s not in bootloader after reboot", monitor.getSerialNumber())); } } /** * @param monitor * @throws DeviceNotAvailableException */ protected void handleDeviceBootloaderUnresponsive(IDeviceStateMonitor monitor) throws DeviceNotAvailableException { CLog.i("Found device %s in fastboot but potentially unresponsive.", monitor.getSerialNumber()); // TODO: retry reboot getRunUtil().runTimedCmd(20*1000, "fastboot", "-s", monitor.getSerialNumber(), "reboot-bootloader"); // wait for device to reboot monitor.waitForDeviceNotAvailable(20*1000); if (!monitor.waitForDeviceBootloader(mBootloaderWaitTime)) { throw new DeviceNotAvailableException(String.format( "Device %s not in bootloader after reboot", monitor.getSerialNumber())); } } /** * Reboot device into bootloader. * * @param device the {@link IDevice} to reboot. */ protected void rebootDeviceIntoBootloader(IDevice device) { try { device.reboot("bootloader"); } catch (IOException e) { Log.w(LOG_TAG, String.format("failed to reboot %s: %s", device.getSerialNumber(), e.getMessage())); } catch (TimeoutException e) { Log.w(LOG_TAG, String.format("failed to reboot %s: timeout", device.getSerialNumber())); } catch (AdbCommandRejectedException e) { Log.w(LOG_TAG, String.format("failed to reboot %s: %s", device.getSerialNumber(), e.getMessage())); } } /** * Reboot device into bootloader. * * @param device the {@link IDevice} to reboot. */ protected void rebootDevice(IDevice device) { try { device.reboot(null); } catch (IOException e) { Log.w(LOG_TAG, String.format("failed to reboot %s: %s", device.getSerialNumber(), e.getMessage())); } catch (TimeoutException e) { Log.w(LOG_TAG, String.format("failed to reboot %s: timeout", device.getSerialNumber())); } catch (AdbCommandRejectedException e) { Log.w(LOG_TAG, String.format("failed to reboot %s: %s", device.getSerialNumber(), e.getMessage())); } } /** * Handle situation where device is not available when expected to be in bootloader. * * @param monitor the {@link IDeviceStateMonitor} * @throws DeviceNotAvailableException */ protected void handleDeviceBootloaderNotAvailable(final IDeviceStateMonitor monitor) throws DeviceNotAvailableException { throw new DeviceNotAvailableException(String.format( "Could not find device %s in bootloader", monitor.getSerialNumber())); } /** * {@inheritDoc} */ @Override public void recoverDeviceRecovery(IDeviceStateMonitor monitor) throws DeviceNotAvailableException { throw new DeviceNotAvailableException("device recovery not implemented"); } } ~~~ 这个类的方法中具体讲了如何实现重连机制,有兴趣的可以详细了解。我不太感兴趣,就一笔带过了。