| #!/usr/bin/env python3.4 |
| # |
| # Copyright 2017 - 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. |
| |
| import logging |
| import time |
| |
| SL4A_SERVICE_SETUP_TIME = 5 |
| |
| |
| class OtaError(Exception): |
| """Raised when an error in the OTA Update process occurs.""" |
| |
| |
| class OtaRunner(object): |
| """The base class for all OTA Update Runners.""" |
| |
| def __init__(self, ota_tool, android_device): |
| self.ota_tool = ota_tool |
| self.android_device = android_device |
| self.serial = self.android_device.serial |
| |
| def _update(self): |
| logging.info('Stopping services.') |
| self.android_device.stop_services() |
| logging.info('Beginning tool.') |
| self.ota_tool.update(self) |
| logging.info('Tool finished. Waiting for boot completion.') |
| self.android_device.wait_for_boot_completion() |
| logging.info('Boot completed. Rooting adb.') |
| self.android_device.root_adb() |
| logging.info('Root complete. Installing new SL4A.') |
| output = self.android_device.adb.install('-r %s' % self.get_sl4a_apk) |
| logging.info('SL4A install output: %s' % output) |
| time.sleep(SL4A_SERVICE_SETUP_TIME) |
| logging.info('Starting services.') |
| self.android_device.start_services() |
| logging.info('Services started. Running ota tool cleanup.') |
| self.ota_tool.cleanup(self) |
| logging.info('Cleanup complete.') |
| |
| def can_update(self): |
| """Whether or not an update package is available for the device.""" |
| return NotImplementedError() |
| |
| def get_ota_package(self): |
| raise NotImplementedError() |
| |
| def get_sl4a_apk(self): |
| raise NotImplementedError() |
| |
| |
| class SingleUseOtaRunner(OtaRunner): |
| """A single use OtaRunner. |
| |
| SingleUseOtaRunners can only be ran once. If a user attempts to run it more |
| than once, an error will be thrown. Users can avoid the error by checking |
| can_update() before calling update(). |
| """ |
| |
| def __init__(self, ota_tool, android_device, ota_package, sl4a_apk): |
| super(SingleUseOtaRunner, self).__init__(ota_tool, android_device) |
| self._ota_package = ota_package |
| self._sl4a_apk = sl4a_apk |
| self._called = False |
| |
| def can_update(self): |
| return not self._called |
| |
| def update(self): |
| """Starts the update process.""" |
| if not self.can_update(): |
| raise OtaError('A SingleUseOtaTool instance cannot update a phone ' |
| 'multiple times.') |
| self._called = True |
| self._update() |
| |
| def get_ota_package(self): |
| return self._ota_package |
| |
| def get_sl4a_apk(self): |
| return self._sl4a_apk |
| |
| |
| class MultiUseOtaRunner(OtaRunner): |
| """A multiple use OtaRunner. |
| |
| MultiUseOtaRunner can only be ran for as many times as there have been |
| packages provided to them. If a user attempts to run it more than the number |
| of provided packages, an error will be thrown. Users can avoid the error by |
| checking can_update() before calling update(). |
| """ |
| |
| def __init__(self, ota_tool, android_device, ota_packages, sl4a_apks): |
| super(MultiUseOtaRunner, self).__init__(ota_tool, android_device) |
| self._ota_packages = ota_packages |
| self._sl4a_apks = sl4a_apks |
| self.current_update_number = 0 |
| |
| def can_update(self): |
| return not self.current_update_number == len(self._ota_packages) |
| |
| def update(self): |
| """Starts the update process.""" |
| if not self.can_update(): |
| raise OtaError('This MultiUseOtaRunner has already updated all ' |
| 'given packages onto the phone.') |
| self._update() |
| self.current_update_number += 1 |
| |
| def get_ota_package(self): |
| return self._ota_packages[self.current_update_number] |
| |
| def get_sl4a_apk(self): |
| return self._sl4a_apks[self.current_update_number] |