xref: /aosp_15_r20/build/make/tools/releasetools/find_shareduid_violation.py (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
1*9e94795aSAndroid Build Coastguard Worker#!/usr/bin/env python
2*9e94795aSAndroid Build Coastguard Worker#
3*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2019 The Android Open Source Project
4*9e94795aSAndroid Build Coastguard Worker#
5*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*9e94795aSAndroid Build Coastguard Worker#
9*9e94795aSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*9e94795aSAndroid Build Coastguard Worker#
11*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*9e94795aSAndroid Build Coastguard Worker# limitations under the License.
16*9e94795aSAndroid Build Coastguard Worker#
17*9e94795aSAndroid Build Coastguard Worker"""Find APK sharedUserId violators.
18*9e94795aSAndroid Build Coastguard Worker
19*9e94795aSAndroid Build Coastguard WorkerUsage: find_shareduid_violation [args]
20*9e94795aSAndroid Build Coastguard Worker
21*9e94795aSAndroid Build Coastguard Worker  --product_out
22*9e94795aSAndroid Build Coastguard Worker    PRODUCT_OUT directory
23*9e94795aSAndroid Build Coastguard Worker
24*9e94795aSAndroid Build Coastguard Worker  --aapt
25*9e94795aSAndroid Build Coastguard Worker    Path to aapt or aapt2
26*9e94795aSAndroid Build Coastguard Worker
27*9e94795aSAndroid Build Coastguard Worker  --copy_out_system
28*9e94795aSAndroid Build Coastguard Worker    TARGET_COPY_OUT_SYSTEM
29*9e94795aSAndroid Build Coastguard Worker
30*9e94795aSAndroid Build Coastguard Worker  --copy_out_vendor_
31*9e94795aSAndroid Build Coastguard Worker    TARGET_COPY_OUT_VENDOR
32*9e94795aSAndroid Build Coastguard Worker
33*9e94795aSAndroid Build Coastguard Worker  --copy_out_product
34*9e94795aSAndroid Build Coastguard Worker    TARGET_COPY_OUT_PRODUCT
35*9e94795aSAndroid Build Coastguard Worker
36*9e94795aSAndroid Build Coastguard Worker  --copy_out_system_ext
37*9e94795aSAndroid Build Coastguard Worker    TARGET_COPY_OUT_SYSTEM_EXT
38*9e94795aSAndroid Build Coastguard Worker"""
39*9e94795aSAndroid Build Coastguard Worker
40*9e94795aSAndroid Build Coastguard Workerimport json
41*9e94795aSAndroid Build Coastguard Workerimport logging
42*9e94795aSAndroid Build Coastguard Workerimport os
43*9e94795aSAndroid Build Coastguard Workerimport re
44*9e94795aSAndroid Build Coastguard Workerimport subprocess
45*9e94795aSAndroid Build Coastguard Workerimport sys
46*9e94795aSAndroid Build Coastguard Worker
47*9e94795aSAndroid Build Coastguard Workerfrom collections import defaultdict
48*9e94795aSAndroid Build Coastguard Workerfrom glob import glob
49*9e94795aSAndroid Build Coastguard Worker
50*9e94795aSAndroid Build Coastguard Workerimport common
51*9e94795aSAndroid Build Coastguard Worker
52*9e94795aSAndroid Build Coastguard Workerlogger = logging.getLogger(__name__)
53*9e94795aSAndroid Build Coastguard Worker
54*9e94795aSAndroid Build Coastguard WorkerOPTIONS = common.OPTIONS
55*9e94795aSAndroid Build Coastguard WorkerOPTIONS.product_out = os.environ.get("PRODUCT_OUT")
56*9e94795aSAndroid Build Coastguard WorkerOPTIONS.aapt = "aapt2"
57*9e94795aSAndroid Build Coastguard WorkerOPTIONS.copy_out_system = "system"
58*9e94795aSAndroid Build Coastguard WorkerOPTIONS.copy_out_vendor = "vendor"
59*9e94795aSAndroid Build Coastguard WorkerOPTIONS.copy_out_product = "product"
60*9e94795aSAndroid Build Coastguard WorkerOPTIONS.copy_out_system_ext = "system_ext"
61*9e94795aSAndroid Build Coastguard Worker
62*9e94795aSAndroid Build Coastguard Worker
63*9e94795aSAndroid Build Coastguard Workerdef execute(cmd):
64*9e94795aSAndroid Build Coastguard Worker  p = subprocess.Popen(
65*9e94795aSAndroid Build Coastguard Worker      cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
66*9e94795aSAndroid Build Coastguard Worker  out, err = map(lambda b: b.decode("utf-8"), p.communicate())
67*9e94795aSAndroid Build Coastguard Worker  return p.returncode == 0, out, err
68*9e94795aSAndroid Build Coastguard Worker
69*9e94795aSAndroid Build Coastguard Worker
70*9e94795aSAndroid Build Coastguard Workerdef make_aapt_cmds(aapt, apk):
71*9e94795aSAndroid Build Coastguard Worker  return [
72*9e94795aSAndroid Build Coastguard Worker      aapt + " dump " + apk + " --file AndroidManifest.xml",
73*9e94795aSAndroid Build Coastguard Worker      aapt + " dump xmltree " + apk + " --file AndroidManifest.xml"
74*9e94795aSAndroid Build Coastguard Worker  ]
75*9e94795aSAndroid Build Coastguard Worker
76*9e94795aSAndroid Build Coastguard Worker
77*9e94795aSAndroid Build Coastguard Workerdef extract_shared_uid(aapt, apk):
78*9e94795aSAndroid Build Coastguard Worker  for cmd in make_aapt_cmds(aapt, apk):
79*9e94795aSAndroid Build Coastguard Worker    success, manifest, error_msg = execute(cmd)
80*9e94795aSAndroid Build Coastguard Worker    if success:
81*9e94795aSAndroid Build Coastguard Worker      break
82*9e94795aSAndroid Build Coastguard Worker  else:
83*9e94795aSAndroid Build Coastguard Worker    logger.error(error_msg)
84*9e94795aSAndroid Build Coastguard Worker    sys.exit()
85*9e94795aSAndroid Build Coastguard Worker
86*9e94795aSAndroid Build Coastguard Worker  pattern = re.compile(r"sharedUserId.*=\"([^\"]*)")
87*9e94795aSAndroid Build Coastguard Worker
88*9e94795aSAndroid Build Coastguard Worker  for line in manifest.split("\n"):
89*9e94795aSAndroid Build Coastguard Worker    match = pattern.search(line)
90*9e94795aSAndroid Build Coastguard Worker    if match:
91*9e94795aSAndroid Build Coastguard Worker      return match.group(1)
92*9e94795aSAndroid Build Coastguard Worker  return None
93*9e94795aSAndroid Build Coastguard Worker
94*9e94795aSAndroid Build Coastguard Worker
95*9e94795aSAndroid Build Coastguard Workerdef FindShareduidViolation(product_out, partition_map, aapt="aapt2"):
96*9e94795aSAndroid Build Coastguard Worker  """Find sharedUserId violators in the given partitions.
97*9e94795aSAndroid Build Coastguard Worker
98*9e94795aSAndroid Build Coastguard Worker  Args:
99*9e94795aSAndroid Build Coastguard Worker    product_out: The base directory containing the partition directories.
100*9e94795aSAndroid Build Coastguard Worker    partition_map: A map of partition name -> directory name.
101*9e94795aSAndroid Build Coastguard Worker    aapt: The name of the aapt binary. Defaults to aapt2.
102*9e94795aSAndroid Build Coastguard Worker
103*9e94795aSAndroid Build Coastguard Worker  Returns:
104*9e94795aSAndroid Build Coastguard Worker    A string containing a JSON object describing the shared UIDs.
105*9e94795aSAndroid Build Coastguard Worker  """
106*9e94795aSAndroid Build Coastguard Worker  shareduid_app_dict = defaultdict(lambda: defaultdict(list))
107*9e94795aSAndroid Build Coastguard Worker
108*9e94795aSAndroid Build Coastguard Worker  for part, location in partition_map.items():
109*9e94795aSAndroid Build Coastguard Worker    for f in glob(os.path.join(product_out, location, "*", "*", "*.apk")):
110*9e94795aSAndroid Build Coastguard Worker      apk_file = os.path.basename(f)
111*9e94795aSAndroid Build Coastguard Worker      shared_uid = extract_shared_uid(aapt, f)
112*9e94795aSAndroid Build Coastguard Worker
113*9e94795aSAndroid Build Coastguard Worker      if shared_uid is None:
114*9e94795aSAndroid Build Coastguard Worker        continue
115*9e94795aSAndroid Build Coastguard Worker      shareduid_app_dict[shared_uid][part].append(apk_file)
116*9e94795aSAndroid Build Coastguard Worker
117*9e94795aSAndroid Build Coastguard Worker  # Only output sharedUserId values that appear in >1 partition.
118*9e94795aSAndroid Build Coastguard Worker  output = {}
119*9e94795aSAndroid Build Coastguard Worker  for uid, partitions in shareduid_app_dict.items():
120*9e94795aSAndroid Build Coastguard Worker    if len(partitions) > 1:
121*9e94795aSAndroid Build Coastguard Worker      output[uid] = shareduid_app_dict[uid]
122*9e94795aSAndroid Build Coastguard Worker
123*9e94795aSAndroid Build Coastguard Worker  return json.dumps(output, indent=2, sort_keys=True)
124*9e94795aSAndroid Build Coastguard Worker
125*9e94795aSAndroid Build Coastguard Worker
126*9e94795aSAndroid Build Coastguard Workerdef main():
127*9e94795aSAndroid Build Coastguard Worker  common.InitLogging()
128*9e94795aSAndroid Build Coastguard Worker
129*9e94795aSAndroid Build Coastguard Worker  def option_handler(o, a):
130*9e94795aSAndroid Build Coastguard Worker    if o == "--product_out":
131*9e94795aSAndroid Build Coastguard Worker      OPTIONS.product_out = a
132*9e94795aSAndroid Build Coastguard Worker    elif o == "--aapt":
133*9e94795aSAndroid Build Coastguard Worker      OPTIONS.aapt = a
134*9e94795aSAndroid Build Coastguard Worker    elif o == "--copy_out_system":
135*9e94795aSAndroid Build Coastguard Worker      OPTIONS.copy_out_system = a
136*9e94795aSAndroid Build Coastguard Worker    elif o == "--copy_out_vendor":
137*9e94795aSAndroid Build Coastguard Worker      OPTIONS.copy_out_vendor = a
138*9e94795aSAndroid Build Coastguard Worker    elif o == "--copy_out_product":
139*9e94795aSAndroid Build Coastguard Worker      OPTIONS.copy_out_product = a
140*9e94795aSAndroid Build Coastguard Worker    elif o == "--copy_out_system_ext":
141*9e94795aSAndroid Build Coastguard Worker      OPTIONS.copy_out_system_ext = a
142*9e94795aSAndroid Build Coastguard Worker    else:
143*9e94795aSAndroid Build Coastguard Worker      return False
144*9e94795aSAndroid Build Coastguard Worker    return True
145*9e94795aSAndroid Build Coastguard Worker
146*9e94795aSAndroid Build Coastguard Worker  args = common.ParseOptions(
147*9e94795aSAndroid Build Coastguard Worker      sys.argv[1:],
148*9e94795aSAndroid Build Coastguard Worker      __doc__,
149*9e94795aSAndroid Build Coastguard Worker      extra_long_opts=[
150*9e94795aSAndroid Build Coastguard Worker          "product_out=",
151*9e94795aSAndroid Build Coastguard Worker          "aapt=",
152*9e94795aSAndroid Build Coastguard Worker          "copy_out_system=",
153*9e94795aSAndroid Build Coastguard Worker          "copy_out_vendor=",
154*9e94795aSAndroid Build Coastguard Worker          "copy_out_product=",
155*9e94795aSAndroid Build Coastguard Worker          "copy_out_system_ext=",
156*9e94795aSAndroid Build Coastguard Worker      ],
157*9e94795aSAndroid Build Coastguard Worker      extra_option_handler=option_handler)
158*9e94795aSAndroid Build Coastguard Worker
159*9e94795aSAndroid Build Coastguard Worker  if args:
160*9e94795aSAndroid Build Coastguard Worker    common.Usage(__doc__)
161*9e94795aSAndroid Build Coastguard Worker    sys.exit(1)
162*9e94795aSAndroid Build Coastguard Worker
163*9e94795aSAndroid Build Coastguard Worker  partition_map = {
164*9e94795aSAndroid Build Coastguard Worker      "system": OPTIONS.copy_out_system,
165*9e94795aSAndroid Build Coastguard Worker      "vendor": OPTIONS.copy_out_vendor,
166*9e94795aSAndroid Build Coastguard Worker      "product": OPTIONS.copy_out_product,
167*9e94795aSAndroid Build Coastguard Worker      "system_ext": OPTIONS.copy_out_system_ext,
168*9e94795aSAndroid Build Coastguard Worker  }
169*9e94795aSAndroid Build Coastguard Worker
170*9e94795aSAndroid Build Coastguard Worker  print(
171*9e94795aSAndroid Build Coastguard Worker      FindShareduidViolation(OPTIONS.product_out, partition_map, OPTIONS.aapt))
172*9e94795aSAndroid Build Coastguard Worker
173*9e94795aSAndroid Build Coastguard Worker
174*9e94795aSAndroid Build Coastguard Workerif __name__ == "__main__":
175*9e94795aSAndroid Build Coastguard Worker  main()
176