1*35238bceSAndroid Build Coastguard Worker# -*- coding: utf-8 -*- 2*35238bceSAndroid Build Coastguard Worker 3*35238bceSAndroid Build Coastguard Worker#------------------------------------------------------------------------- 4*35238bceSAndroid Build Coastguard Worker# drawElements Quality Program utilities 5*35238bceSAndroid Build Coastguard Worker# -------------------------------------- 6*35238bceSAndroid Build Coastguard Worker# 7*35238bceSAndroid Build Coastguard Worker# Copyright 2017 The Android Open Source Project 8*35238bceSAndroid Build Coastguard Worker# 9*35238bceSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 10*35238bceSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 11*35238bceSAndroid Build Coastguard Worker# You may obtain a copy of the License at 12*35238bceSAndroid Build Coastguard Worker# 13*35238bceSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 14*35238bceSAndroid Build Coastguard Worker# 15*35238bceSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 16*35238bceSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 17*35238bceSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18*35238bceSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 19*35238bceSAndroid Build Coastguard Worker# limitations under the License. 20*35238bceSAndroid Build Coastguard Worker# 21*35238bceSAndroid Build Coastguard Worker#------------------------------------------------------------------------- 22*35238bceSAndroid Build Coastguard Worker 23*35238bceSAndroid Build Coastguard Workerimport os 24*35238bceSAndroid Build Coastguard Workerimport re 25*35238bceSAndroid Build Coastguard Workerimport sys 26*35238bceSAndroid Build Coastguard Workerimport argparse 27*35238bceSAndroid Build Coastguard Workerimport threading 28*35238bceSAndroid Build Coastguard Workerimport subprocess 29*35238bceSAndroid Build Coastguard Worker 30*35238bceSAndroid Build Coastguard Workerfrom build_apk import findSDK 31*35238bceSAndroid Build Coastguard Workerfrom build_apk import getDefaultBuildRoot 32*35238bceSAndroid Build Coastguard Workerfrom build_apk import getPackageAndLibrariesForTarget 33*35238bceSAndroid Build Coastguard Workerfrom build_apk import getBuildRootRelativeAPKPath 34*35238bceSAndroid Build Coastguard Workerfrom build_apk import parsePackageName 35*35238bceSAndroid Build Coastguard Worker 36*35238bceSAndroid Build Coastguard Worker# Import from <root>/scripts 37*35238bceSAndroid Build Coastguard Workersys.path.append(os.path.join(os.path.dirname(__file__), "..")) 38*35238bceSAndroid Build Coastguard Worker 39*35238bceSAndroid Build Coastguard Workerfrom ctsbuild.common import * 40*35238bceSAndroid Build Coastguard Worker 41*35238bceSAndroid Build Coastguard Workerclass Device: 42*35238bceSAndroid Build Coastguard Worker def __init__(self, serial, product, model, device): 43*35238bceSAndroid Build Coastguard Worker self.serial = serial 44*35238bceSAndroid Build Coastguard Worker self.product = product 45*35238bceSAndroid Build Coastguard Worker self.model = model 46*35238bceSAndroid Build Coastguard Worker self.device = device 47*35238bceSAndroid Build Coastguard Worker 48*35238bceSAndroid Build Coastguard Worker def __str__ (self): 49*35238bceSAndroid Build Coastguard Worker return "%s: {product: %s, model: %s, device: %s}" % (self.serial, self.product, self.model, self.device) 50*35238bceSAndroid Build Coastguard Worker 51*35238bceSAndroid Build Coastguard Workerdef getDevices (adbPath): 52*35238bceSAndroid Build Coastguard Worker proc = subprocess.Popen([adbPath, 'devices', '-l'], stdout=subprocess.PIPE) 53*35238bceSAndroid Build Coastguard Worker (stdout, stderr) = proc.communicate() 54*35238bceSAndroid Build Coastguard Worker 55*35238bceSAndroid Build Coastguard Worker if proc.returncode != 0: 56*35238bceSAndroid Build Coastguard Worker raise Exception("adb devices -l failed, got %d" % proc.returncode) 57*35238bceSAndroid Build Coastguard Worker 58*35238bceSAndroid Build Coastguard Worker ptrn = re.compile(r'^([a-zA-Z0-9\.\-:]+)\s+.*product:([^\s]+)\s+model:([^\s]+)\s+device:([^\s]+)') 59*35238bceSAndroid Build Coastguard Worker devices = [] 60*35238bceSAndroid Build Coastguard Worker for line in stdout.splitlines()[1:]: 61*35238bceSAndroid Build Coastguard Worker if len(line.strip()) == 0: 62*35238bceSAndroid Build Coastguard Worker continue 63*35238bceSAndroid Build Coastguard Worker 64*35238bceSAndroid Build Coastguard Worker m = ptrn.match(line.decode('utf-8')) 65*35238bceSAndroid Build Coastguard Worker if m == None: 66*35238bceSAndroid Build Coastguard Worker print("WARNING: Failed to parse device info '%s'" % line) 67*35238bceSAndroid Build Coastguard Worker continue 68*35238bceSAndroid Build Coastguard Worker 69*35238bceSAndroid Build Coastguard Worker devices.append(Device(m.group(1), m.group(2), m.group(3), m.group(4))) 70*35238bceSAndroid Build Coastguard Worker 71*35238bceSAndroid Build Coastguard Worker return devices 72*35238bceSAndroid Build Coastguard Worker 73*35238bceSAndroid Build Coastguard Workerdef execWithPrintPrefix (args, linePrefix="", failOnNonZeroExit=True): 74*35238bceSAndroid Build Coastguard Worker 75*35238bceSAndroid Build Coastguard Worker def readApplyPrefixAndPrint (source, prefix, sink): 76*35238bceSAndroid Build Coastguard Worker while True: 77*35238bceSAndroid Build Coastguard Worker line = source.readline() 78*35238bceSAndroid Build Coastguard Worker if len(line) == 0: # EOF 79*35238bceSAndroid Build Coastguard Worker break; 80*35238bceSAndroid Build Coastguard Worker sink.write(prefix + line.decode('utf-8')) 81*35238bceSAndroid Build Coastguard Worker 82*35238bceSAndroid Build Coastguard Worker process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 83*35238bceSAndroid Build Coastguard Worker stdoutJob = threading.Thread(target=readApplyPrefixAndPrint, args=(process.stdout, linePrefix, sys.stdout)) 84*35238bceSAndroid Build Coastguard Worker stderrJob = threading.Thread(target=readApplyPrefixAndPrint, args=(process.stderr, linePrefix, sys.stderr)) 85*35238bceSAndroid Build Coastguard Worker stdoutJob.start() 86*35238bceSAndroid Build Coastguard Worker stderrJob.start() 87*35238bceSAndroid Build Coastguard Worker retcode = process.wait() 88*35238bceSAndroid Build Coastguard Worker if failOnNonZeroExit and retcode != 0: 89*35238bceSAndroid Build Coastguard Worker raise Exception("Failed to execute '%s', got %d" % (str(args), retcode)) 90*35238bceSAndroid Build Coastguard Worker 91*35238bceSAndroid Build Coastguard Workerdef serialApply (f, argsList): 92*35238bceSAndroid Build Coastguard Worker for args in argsList: 93*35238bceSAndroid Build Coastguard Worker f(*args) 94*35238bceSAndroid Build Coastguard Worker 95*35238bceSAndroid Build Coastguard Workerdef parallelApply (f, argsList): 96*35238bceSAndroid Build Coastguard Worker class ErrorCode: 97*35238bceSAndroid Build Coastguard Worker def __init__ (self): 98*35238bceSAndroid Build Coastguard Worker self.error = None; 99*35238bceSAndroid Build Coastguard Worker 100*35238bceSAndroid Build Coastguard Worker def applyAndCaptureError (func, args, errorCode): 101*35238bceSAndroid Build Coastguard Worker try: 102*35238bceSAndroid Build Coastguard Worker func(*args) 103*35238bceSAndroid Build Coastguard Worker except: 104*35238bceSAndroid Build Coastguard Worker errorCode.error = sys.exc_info() 105*35238bceSAndroid Build Coastguard Worker 106*35238bceSAndroid Build Coastguard Worker errorCode = ErrorCode() 107*35238bceSAndroid Build Coastguard Worker jobs = [] 108*35238bceSAndroid Build Coastguard Worker for args in argsList: 109*35238bceSAndroid Build Coastguard Worker job = threading.Thread(target=applyAndCaptureError, args=(f, args, errorCode)) 110*35238bceSAndroid Build Coastguard Worker job.start() 111*35238bceSAndroid Build Coastguard Worker jobs.append(job) 112*35238bceSAndroid Build Coastguard Worker 113*35238bceSAndroid Build Coastguard Worker for job in jobs: 114*35238bceSAndroid Build Coastguard Worker job.join() 115*35238bceSAndroid Build Coastguard Worker 116*35238bceSAndroid Build Coastguard Worker if errorCode.error: 117*35238bceSAndroid Build Coastguard Worker raise errorCode.error[0](errorCode.error[1]).with_traceback(errorCode.error[2]) 118*35238bceSAndroid Build Coastguard Worker 119*35238bceSAndroid Build Coastguard Workerdef uninstall (adbPath, packageName, extraArgs = [], printPrefix=""): 120*35238bceSAndroid Build Coastguard Worker print(printPrefix + "Removing existing %s...\n" % packageName,) 121*35238bceSAndroid Build Coastguard Worker execWithPrintPrefix([adbPath] + extraArgs + [ 122*35238bceSAndroid Build Coastguard Worker 'uninstall', 123*35238bceSAndroid Build Coastguard Worker packageName 124*35238bceSAndroid Build Coastguard Worker ], printPrefix, failOnNonZeroExit=False) 125*35238bceSAndroid Build Coastguard Worker print(printPrefix + "Remove complete\n",) 126*35238bceSAndroid Build Coastguard Worker 127*35238bceSAndroid Build Coastguard Workerdef install (adbPath, apkPath, extraArgs = [], printPrefix=""): 128*35238bceSAndroid Build Coastguard Worker print(printPrefix + "Installing %s...\n" % apkPath,) 129*35238bceSAndroid Build Coastguard Worker execWithPrintPrefix([adbPath] + extraArgs + [ 130*35238bceSAndroid Build Coastguard Worker 'install', 131*35238bceSAndroid Build Coastguard Worker '-g', 132*35238bceSAndroid Build Coastguard Worker apkPath 133*35238bceSAndroid Build Coastguard Worker ], printPrefix) 134*35238bceSAndroid Build Coastguard Worker print(printPrefix + "Install complete\n",) 135*35238bceSAndroid Build Coastguard Worker 136*35238bceSAndroid Build Coastguard Workerdef installToDevice (device, adbPath, packageName, apkPath, printPrefix=""): 137*35238bceSAndroid Build Coastguard Worker if len(printPrefix) == 0: 138*35238bceSAndroid Build Coastguard Worker print("Installing to %s (%s)...\n" % (device.serial, device.model), end='') 139*35238bceSAndroid Build Coastguard Worker else: 140*35238bceSAndroid Build Coastguard Worker print(printPrefix + "Installing to %s\n" % device.serial, end='') 141*35238bceSAndroid Build Coastguard Worker 142*35238bceSAndroid Build Coastguard Worker uninstall(adbPath, packageName, ['-s', device.serial], printPrefix) 143*35238bceSAndroid Build Coastguard Worker install(adbPath, apkPath, ['-s', device.serial], printPrefix) 144*35238bceSAndroid Build Coastguard Worker 145*35238bceSAndroid Build Coastguard Workerdef installToDevices (devices, doParallel, adbPath, packageName, apkPath): 146*35238bceSAndroid Build Coastguard Worker padLen = max([len(device.model) for device in devices])+1 147*35238bceSAndroid Build Coastguard Worker if doParallel: 148*35238bceSAndroid Build Coastguard Worker parallelApply(installToDevice, [(device, adbPath, packageName, apkPath, ("(%s):%s" % (device.model, ' ' * (padLen - len(device.model))))) for device in devices]); 149*35238bceSAndroid Build Coastguard Worker else: 150*35238bceSAndroid Build Coastguard Worker serialApply(installToDevice, [(device, adbPath, packageName, apkPath) for device in devices]); 151*35238bceSAndroid Build Coastguard Worker 152*35238bceSAndroid Build Coastguard Workerdef installToAllDevices (doParallel, adbPath, packageName, apkPath): 153*35238bceSAndroid Build Coastguard Worker devices = getDevices(adbPath) 154*35238bceSAndroid Build Coastguard Worker installToDevices(devices, doParallel, adbPath, packageName, apkPath) 155*35238bceSAndroid Build Coastguard Worker 156*35238bceSAndroid Build Coastguard Workerdef getAPKPath (buildRootPath, target): 157*35238bceSAndroid Build Coastguard Worker package = getPackageAndLibrariesForTarget(target)[0] 158*35238bceSAndroid Build Coastguard Worker return os.path.join(buildRootPath, getBuildRootRelativeAPKPath(package)) 159*35238bceSAndroid Build Coastguard Worker 160*35238bceSAndroid Build Coastguard Workerdef getPackageName (target): 161*35238bceSAndroid Build Coastguard Worker package = getPackageAndLibrariesForTarget(target)[0] 162*35238bceSAndroid Build Coastguard Worker manifestPath = os.path.join(DEQP_DIR, "android", package.appDirName, "AndroidManifest.xml") 163*35238bceSAndroid Build Coastguard Worker 164*35238bceSAndroid Build Coastguard Worker return parsePackageName(manifestPath) 165*35238bceSAndroid Build Coastguard Worker 166*35238bceSAndroid Build Coastguard Workerdef findADB (): 167*35238bceSAndroid Build Coastguard Worker adbInPath = which("adb") 168*35238bceSAndroid Build Coastguard Worker if adbInPath != None: 169*35238bceSAndroid Build Coastguard Worker return adbInPath 170*35238bceSAndroid Build Coastguard Worker 171*35238bceSAndroid Build Coastguard Worker sdkPath = findSDK() 172*35238bceSAndroid Build Coastguard Worker if sdkPath != None: 173*35238bceSAndroid Build Coastguard Worker adbInSDK = os.path.join(sdkPath, "platform-tools", "adb") 174*35238bceSAndroid Build Coastguard Worker if os.path.isfile(adbInSDK): 175*35238bceSAndroid Build Coastguard Worker return adbInSDK 176*35238bceSAndroid Build Coastguard Worker 177*35238bceSAndroid Build Coastguard Worker return None 178*35238bceSAndroid Build Coastguard Worker 179*35238bceSAndroid Build Coastguard Workerdef parseArgs (): 180*35238bceSAndroid Build Coastguard Worker defaultADBPath = findADB() 181*35238bceSAndroid Build Coastguard Worker defaultBuildRoot = getDefaultBuildRoot() 182*35238bceSAndroid Build Coastguard Worker 183*35238bceSAndroid Build Coastguard Worker parser = argparse.ArgumentParser(os.path.basename(__file__), 184*35238bceSAndroid Build Coastguard Worker formatter_class=argparse.ArgumentDefaultsHelpFormatter) 185*35238bceSAndroid Build Coastguard Worker parser.add_argument('--build-root', 186*35238bceSAndroid Build Coastguard Worker dest='buildRoot', 187*35238bceSAndroid Build Coastguard Worker default=defaultBuildRoot, 188*35238bceSAndroid Build Coastguard Worker help="Root build directory") 189*35238bceSAndroid Build Coastguard Worker parser.add_argument('--adb', 190*35238bceSAndroid Build Coastguard Worker dest='adbPath', 191*35238bceSAndroid Build Coastguard Worker default=defaultADBPath, 192*35238bceSAndroid Build Coastguard Worker help="ADB binary path", 193*35238bceSAndroid Build Coastguard Worker required=(True if defaultADBPath == None else False)) 194*35238bceSAndroid Build Coastguard Worker parser.add_argument('--target', 195*35238bceSAndroid Build Coastguard Worker dest='target', 196*35238bceSAndroid Build Coastguard Worker help='Build target', 197*35238bceSAndroid Build Coastguard Worker choices=['deqp', 'openglcts'], 198*35238bceSAndroid Build Coastguard Worker default='deqp') 199*35238bceSAndroid Build Coastguard Worker parser.add_argument('-p', '--parallel', 200*35238bceSAndroid Build Coastguard Worker dest='doParallel', 201*35238bceSAndroid Build Coastguard Worker action="store_true", 202*35238bceSAndroid Build Coastguard Worker help="Install package in parallel") 203*35238bceSAndroid Build Coastguard Worker parser.add_argument('-s', '--serial', 204*35238bceSAndroid Build Coastguard Worker dest='serial', 205*35238bceSAndroid Build Coastguard Worker type=str, 206*35238bceSAndroid Build Coastguard Worker nargs='+', 207*35238bceSAndroid Build Coastguard Worker help="Install package to device with serial number") 208*35238bceSAndroid Build Coastguard Worker parser.add_argument('-a', '--all', 209*35238bceSAndroid Build Coastguard Worker dest='all', 210*35238bceSAndroid Build Coastguard Worker action="store_true", 211*35238bceSAndroid Build Coastguard Worker help="Install to all devices") 212*35238bceSAndroid Build Coastguard Worker 213*35238bceSAndroid Build Coastguard Worker return parser.parse_args() 214*35238bceSAndroid Build Coastguard Worker 215*35238bceSAndroid Build Coastguard Workerif __name__ == "__main__": 216*35238bceSAndroid Build Coastguard Worker args = parseArgs() 217*35238bceSAndroid Build Coastguard Worker packageName = getPackageName(args.target) 218*35238bceSAndroid Build Coastguard Worker apkPath = getAPKPath(args.buildRoot, args.target) 219*35238bceSAndroid Build Coastguard Worker 220*35238bceSAndroid Build Coastguard Worker if not os.path.isfile(apkPath): 221*35238bceSAndroid Build Coastguard Worker die("%s does not exist" % apkPath) 222*35238bceSAndroid Build Coastguard Worker 223*35238bceSAndroid Build Coastguard Worker if args.all: 224*35238bceSAndroid Build Coastguard Worker installToAllDevices(args.doParallel, args.adbPath, packageName, apkPath) 225*35238bceSAndroid Build Coastguard Worker else: 226*35238bceSAndroid Build Coastguard Worker if args.serial == None: 227*35238bceSAndroid Build Coastguard Worker devices = getDevices(args.adbPath) 228*35238bceSAndroid Build Coastguard Worker if len(devices) == 0: 229*35238bceSAndroid Build Coastguard Worker die('No devices connected') 230*35238bceSAndroid Build Coastguard Worker elif len(devices) == 1: 231*35238bceSAndroid Build Coastguard Worker installToDevice(devices[0], args.adbPath, packageName, apkPath) 232*35238bceSAndroid Build Coastguard Worker else: 233*35238bceSAndroid Build Coastguard Worker print("More than one device connected:") 234*35238bceSAndroid Build Coastguard Worker for i in range(0, len(devices)): 235*35238bceSAndroid Build Coastguard Worker print("%3d: %16s %s" % ((i+1), devices[i].serial, devices[i].model)) 236*35238bceSAndroid Build Coastguard Worker 237*35238bceSAndroid Build Coastguard Worker deviceNdx = int(input("Choose device (1-%d): " % len(devices))) 238*35238bceSAndroid Build Coastguard Worker installToDevice(devices[deviceNdx-1], args.adbPath, packageName, apkPath) 239*35238bceSAndroid Build Coastguard Worker else: 240*35238bceSAndroid Build Coastguard Worker devices = getDevices(args.adbPath) 241*35238bceSAndroid Build Coastguard Worker 242*35238bceSAndroid Build Coastguard Worker devices = [dev for dev in devices if dev.serial in args.serial] 243*35238bceSAndroid Build Coastguard Worker devSerials = [dev.serial for dev in devices] 244*35238bceSAndroid Build Coastguard Worker notFounds = [serial for serial in args.serial if not serial in devSerials] 245*35238bceSAndroid Build Coastguard Worker 246*35238bceSAndroid Build Coastguard Worker for notFound in notFounds: 247*35238bceSAndroid Build Coastguard Worker print("Couldn't find device matching serial '%s'" % notFound) 248*35238bceSAndroid Build Coastguard Worker 249*35238bceSAndroid Build Coastguard Worker installToDevices(devices, args.doParallel, args.adbPath, packageName, apkPath) 250