1#!/usr/bin/env python3.4 2# 3# Copyright 2017 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import time 18 19SL4A_SERVICE_SETUP_TIME = 5 20 21 22class OtaError(Exception): 23 """Raised when an error in the OTA Update process occurs.""" 24 25 26class OtaRunner(object): 27 """The base class for all OTA Update Runners.""" 28 29 def __init__(self, ota_tool, android_device): 30 self.ota_tool = ota_tool 31 self.android_device = android_device 32 self.serial = self.android_device.serial 33 34 def _update(self): 35 log = self.android_device.log 36 old_info = self.android_device.adb.getprop('ro.build.fingerprint') 37 log.info('Starting Update. Beginning build info: %s', old_info) 38 log.info('Stopping services.') 39 self.android_device.stop_services() 40 log.info('Beginning tool.') 41 self.ota_tool.update(self) 42 log.info('Tool finished. Waiting for boot completion.') 43 self.android_device.wait_for_boot_completion() 44 new_info = self.android_device.adb.getprop('ro.build.fingerprint') 45 if not old_info or old_info == new_info: 46 raise OtaError('The device was not updated to a new build. ' 47 'Previous build: %s. New build: %s' % (old_info, 48 new_info)) 49 log.info('Boot completed. Rooting adb.') 50 self.android_device.root_adb() 51 log.info('Root complete.') 52 if self.android_device.skip_sl4a: 53 self.android_device.log.info('Skipping SL4A install.') 54 else: 55 for _ in range(3): 56 self.android_device.log.info('Re-installing SL4A from "%s".', 57 self.get_sl4a_apk()) 58 self.android_device.adb.install( 59 '-r -g %s' % self.get_sl4a_apk(), ignore_status=True) 60 time.sleep(SL4A_SERVICE_SETUP_TIME) 61 if self.android_device.is_sl4a_installed(): 62 break 63 log.info('Starting services.') 64 self.android_device.start_services() 65 log.info('Services started. Running ota tool cleanup.') 66 self.ota_tool.cleanup(self) 67 log.info('Cleanup complete.') 68 69 def can_update(self): 70 """Whether or not an update package is available for the device.""" 71 return NotImplementedError() 72 73 def get_ota_package(self): 74 raise NotImplementedError() 75 76 def get_sl4a_apk(self): 77 raise NotImplementedError() 78 79 80class SingleUseOtaRunner(OtaRunner): 81 """A single use OtaRunner. 82 83 SingleUseOtaRunners can only be ran once. If a user attempts to run it more 84 than once, an error will be thrown. Users can avoid the error by checking 85 can_update() before calling update(). 86 """ 87 88 def __init__(self, ota_tool, android_device, ota_package, sl4a_apk): 89 super(SingleUseOtaRunner, self).__init__(ota_tool, android_device) 90 self._ota_package = ota_package 91 self._sl4a_apk = sl4a_apk 92 self._called = False 93 94 def can_update(self): 95 return not self._called 96 97 def update(self): 98 """Starts the update process.""" 99 if not self.can_update(): 100 raise OtaError('A SingleUseOtaTool instance cannot update a phone ' 101 'multiple times.') 102 self._called = True 103 self._update() 104 105 def get_ota_package(self): 106 return self._ota_package 107 108 def get_sl4a_apk(self): 109 return self._sl4a_apk 110 111 112class MultiUseOtaRunner(OtaRunner): 113 """A multiple use OtaRunner. 114 115 MultiUseOtaRunner can only be ran for as many times as there have been 116 packages provided to them. If a user attempts to run it more than the number 117 of provided packages, an error will be thrown. Users can avoid the error by 118 checking can_update() before calling update(). 119 """ 120 121 def __init__(self, ota_tool, android_device, ota_packages, sl4a_apks): 122 super(MultiUseOtaRunner, self).__init__(ota_tool, android_device) 123 self._ota_packages = ota_packages 124 self._sl4a_apks = sl4a_apks 125 self.current_update_number = 0 126 127 def can_update(self): 128 return not self.current_update_number == len(self._ota_packages) 129 130 def update(self): 131 """Starts the update process.""" 132 if not self.can_update(): 133 raise OtaError('This MultiUseOtaRunner has already updated all ' 134 'given packages onto the phone.') 135 self._update() 136 self.current_update_number += 1 137 138 def get_ota_package(self): 139 return self._ota_packages[self.current_update_number] 140 141 def get_sl4a_apk(self): 142 return self._sl4a_apks[self.current_update_number] 143