xref: /aosp_15_r20/external/deqp/scripts/android/install_apk.py (revision 35238bce31c2a825756842865a792f8cf7f89930)
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