Merge "Revert "ART: Add python+debugfs based ART APEX checker""
diff --git a/Android.mk b/Android.mk
index b0a918c..1a5daff 100644
--- a/Android.mk
+++ b/Android.mk
@@ -352,15 +352,13 @@
   # Module with both release and debug variants, as well as
   # additional tools.
   TARGET_RUNTIME_APEX := com.android.runtime.debug
-  APEX_TEST_MODULE := art-check-debug-apex-gen-fakelib
 else
   # Release module (without debug variants nor tools).
   TARGET_RUNTIME_APEX := com.android.runtime.release
-  APEX_TEST_MODULE := art-check-release-apex-gen-fakelib
 endif
 
 LOCAL_MODULE := com.android.runtime
-LOCAL_REQUIRED_MODULES := $(TARGET_RUNTIME_APEX) $(APEX_TEST_MODULE)
+LOCAL_REQUIRED_MODULES := $(TARGET_RUNTIME_APEX)
 
 # Clear locally used variable.
 art_target_include_debug_build :=
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index b1c80cf..9b5c638 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -219,61 +219,3 @@
         },
     },
 }
-
-python_binary_host {
-    name: "art-apex-tester",
-    srcs: ["art_apex_test.py"],
-    main: "art_apex_test.py",
-    version: {
-        py3: {
-            enabled: true,
-        },
-    },
-}
-
-// Genrules so we can run the checker, and empty Java library so that it gets executed.
-
-java_genrule_host {
-    name: "art-check-release-apex-gen",
-    srcs: [":com.android.runtime.release"],
-    tools: [
-        "art-apex-tester",
-        "debugfs",
-        "soong_zip",
-    ],
-    cmd: "$(location art-apex-tester)"
-              + " --debugfs $(location debugfs)"
-              + " --tmpdir $(genDir)"
-              + " --target"
-              + " $(in)"
-         + " && $(location soong_zip) -o $(out)",
-    out: ["art-check-release-apex-gen.srcjar"],
-}
-java_library_host {
-    name: "art-check-release-apex-gen-fakelib",
-    srcs: [":art-check-release-apex-gen"],
-    installable: false,
-}
-
-java_genrule_host {
-    name: "art-check-debug-apex-gen",
-    srcs: [":com.android.runtime.debug"],
-    tools: [
-        "art-apex-tester",
-        "debugfs",
-        "soong_zip",
-    ],
-    cmd: "$(location art-apex-tester)"
-              + " --debugfs $(location debugfs)"
-              + " --tmpdir $(genDir)"
-              + " --target"
-              + " --debug"
-              + " $(in)"
-         + " && $(location soong_zip) -o $(out)",
-    out: ["art-check-debug-apex-gen.srcjar"],
-}
-java_library_host {
-    name: "art-check-debug-apex-gen-fakelib",
-    srcs: [":art-check-debug-apex-gen"],
-    installable: false,
-}
diff --git a/build/apex/art_apex_test.py b/build/apex/art_apex_test.py
deleted file mode 100755
index 5ac2f72..0000000
--- a/build/apex/art_apex_test.py
+++ /dev/null
@@ -1,372 +0,0 @@
-#!/usr/bin/env python3
-
-# Copyright (C) 2019 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 argparse
-import logging
-import os
-import subprocess
-import sys
-import zipfile
-
-logging.basicConfig(format='%(message)s')
-
-class FSObject:
-  def __init__(self, name, is_dir, is_exec, is_symlink):
-    self.name = name
-    self.is_dir = is_dir
-    self.is_exec = is_exec
-    self.is_symlink = is_symlink
-  def __str__(self):
-    return '%s(dir=%r,exec=%r,symlink=%r)' % (self.name, self.is_dir, self.is_exec, self.is_symlink)
-
-class TargetApexProvider:
-  def __init__(self, apex, tmpdir, debugfs):
-    self._tmpdir = tmpdir
-    self._debugfs = debugfs
-    self._folder_cache = {}
-    self._payload = os.path.join(self._tmpdir, 'apex_payload.img')
-    # Extract payload to tmpdir.
-    zip = zipfile.ZipFile(apex)
-    zip.extract('apex_payload.img', tmpdir)
-
-  def __del__(self):
-    # Delete temps.
-    if os.path.exists(self._payload):
-      os.remove(self._payload)
-
-  def get(self, path):
-    dir, name = os.path.split(path)
-    if len(dir) == 0:
-      dir = '/'
-    map = self.read_dir(dir)
-    return map[name] if name in map else None
-
-  def read_dir(self, dir):
-    if dir in self._folder_cache:
-      return self._folder_cache[dir]
-    # Cannot use check_output as it will annoy with stderr.
-    process = subprocess.Popen([self._debugfs, '-R', 'ls -l -p %s' % (dir), self._payload],
-                               stdout=subprocess.PIPE, stderr=subprocess.PIPE,
-                               universal_newlines=True)
-    stdout, stderr = process.communicate()
-    res = str(stdout)
-    map = {}
-    # Debugfs output looks like this:
-    #   debugfs 1.44.4 (18-Aug-2018)
-    #   /12/040755/0/2000/.//
-    #   /2/040755/1000/1000/..//
-    #   /13/100755/0/2000/dalvikvm32/28456/
-    #   /14/100755/0/2000/dexoptanalyzer/20396/
-    #   /15/100755/0/2000/linker/1152724/
-    #   /16/100755/0/2000/dex2oat/563508/
-    #   /17/100755/0/2000/linker64/1605424/
-    #   /18/100755/0/2000/profman/85304/
-    #   /19/100755/0/2000/dalvikvm64/28576/
-    #    |     |   |   |       |        |
-    #    |     |   |   #- gid  #- name  #- size
-    #    |     |   #- uid
-    #    |     #- type and permission bits
-    #    #- inode nr (?)
-    #
-    # Note: could break just on '/' to avoid names with newlines.
-    for line in res.split("\n"):
-      if not line:
-        continue
-      comps = line.split('/')
-      if len(comps) != 8:
-        logging.warn('Could not break and parse line \'%s\'', line)
-        continue
-      bits = comps[2]
-      name = comps[5]
-      if len(bits) != 6:
-        logging.warn('Dont understand bits \'%s\'', bits)
-        continue
-      is_dir = True if bits[1] == '4' else False
-      def is_exec_bit(ch):
-        return True if int(ch) & 1 == 1 else False
-      is_exec = is_exec_bit(bits[3]) and is_exec_bit(bits[4]) and is_exec_bit(bits[5])
-      # TODO: Figure out how this is represented
-      is_symlink = False
-      map[name] = FSObject(name, is_dir, is_exec, is_symlink)
-    self._folder_cache[dir] = map
-    return map
-
-class Checker:
-  def __init__(self, provider):
-    self._provider = provider
-    self._errors = 0
-    self._is_multilib = provider.get('lib64') is not None;
-
-  def fail(self, msg, *args):
-    self._errors += 1
-    logging.error(msg, args)
-
-  def error_count(self):
-    return self._errors
-
-  def check_file(self, file):
-    fs_object = self._provider.get(file)
-    if fs_object is None:
-      self.fail('Could not find %s', file)
-      return False
-    if fs_object.is_dir:
-      self.fail('%s is a directory', file)
-      return False
-    return True
-
-  def check_binary(self, file):
-    path = 'bin/%s' % (file)
-    if not self.check_file(path):
-      return False
-    if not self._provider.get(path).is_exec:
-      self.fail('%s is not executable', path)
-      return False
-    return True
-
-  def check_multilib_binary(self, file):
-    res = self.check_binary('%s32' % (file))
-    if self._is_multilib:
-      res = self.check_binary('%s64' % (file)) and res
-    return res
-
-  def check_binary_symlink(self, file):
-    path = 'bin/%s' % (file)
-    fs_object = self._provider.get(path)
-    if fs_object is None:
-      self.fail('Could not find %s', path)
-      return False
-    if fs_object.is_dir:
-      self.fail('%s is a directory', path)
-      return False
-    if not fs_object.is_symlink:
-      self.fail('%s is not a symlink', path)
-      return False
-    return True
-
-  def check_library(self, file):
-    # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
-    # the precision of this test?
-    res = self.check_file('lib/%s' % (file))
-    if self._is_multilib:
-      res = self.check_file('lib64/%s' % (file)) and res
-    return res
-
-  def check_java_library(self, file):
-    return self.check_file('javalib/%s' % (file))
-
-class ReleaseChecker(Checker):
-  def __init__(self, provider):
-    super().__init__(provider)
-  def __str__(self):
-    return 'Release Checker'
-
-  def run(self):
-    # Check that the mounted image contains an APEX manifest.
-    self.check_file('apex_manifest.json')
-
-    # Check that the mounted image contains ART base binaries.
-    self.check_multilib_binary('dalvikvm')
-    # TODO: Does not work yet (b/119942078).
-    # self.check_binary_symlink('dalvikvm')
-    self.check_binary('dex2oat')
-    self.check_binary('dexoptanalyzer')
-    self.check_binary('profman')
-
-    # oatdump is only in device apex's due to build rules
-    # TODO: Check for it when it is also built for host.
-    # self.check_binary('oatdump')
-
-    # Check that the mounted image contains Android Runtime libraries.
-    self.check_library('libart-compiler.so')
-    self.check_library('libart-dexlayout.so')
-    self.check_library('libart.so')
-    self.check_library('libartbase.so')
-    self.check_library('libdexfile.so')
-    self.check_library('libopenjdkjvm.so')
-    self.check_library('libopenjdkjvmti.so')
-    self.check_library('libprofile.so')
-    # Check that the mounted image contains Android Core libraries.
-    self.check_library('libexpat.so')
-    self.check_library('libjavacore.so')
-    self.check_library('libopenjdk.so')
-    self.check_library('libz.so')
-    self.check_library('libziparchive.so')
-    # Check that the mounted image contains additional required libraries.
-    self.check_library('libadbconnection.so')
-
-    # TODO: Should we check for other libraries, such as:
-    #
-    #   libbacktrace.so
-    #   libbase.so
-    #   liblog.so
-    #   libsigchain.so
-    #   libtombstoned_client.so
-    #   libunwindstack.so
-    #   libvixl.so
-    #   libvixld.so
-    #   ...
-    #
-    # ?
-
-    self.check_java_library('core-oj.jar')
-    self.check_java_library('core-libart.jar')
-    self.check_java_library('okhttp.jar')
-    self.check_java_library('bouncycastle.jar')
-    self.check_java_library('apache-xml.jar')
-
-class DebugChecker(Checker):
-  def __init__(self, provider):
-    super().__init__(provider)
-  def __str__(self):
-    return 'Debug Checker'
-
-  def run(self):
-    # Check that the mounted image contains ART tools binaries.
-    self.check_binary('dexdiag')
-    self.check_binary('dexdump')
-    self.check_binary('dexlist')
-
-    # Check that the mounted image contains ART debug binaries.
-    # TODO(b/123427238): This should probably be dex2oatd, fix!
-    self.check_binary('dex2oatd32')
-    self.check_binary('dexoptanalyzerd')
-    self.check_binary('profmand')
-
-    # Check that the mounted image contains Android Runtime debug libraries.
-    self.check_library('libartbased.so')
-    self.check_library('libartd-compiler.so')
-    self.check_library('libartd-dexlayout.so')
-    self.check_library('libartd.so')
-    self.check_library('libdexfiled.so')
-    self.check_library('libopenjdkjvmd.so')
-    self.check_library('libopenjdkjvmtid.so')
-    self.check_library('libprofiled.so')
-    # Check that the mounted image contains Android Core debug libraries.
-    self.check_library('libopenjdkd.so')
-    # Check that the mounted image contains additional required debug libraries.
-    self.check_library('libadbconnectiond.so')
-
-# Note: do not sys.exit early, for __del__ cleanup.
-def artApexTestMain(args):
-  if not args.host and not args.target and not args.debug:
-    logging.error("None of --host, --target nor --debug set")
-    return 1
-  if args.host and (args.target or args.debug):
-    logging.error("Both of --host and --target|--debug set")
-    return 1
-  if args.debug and not args.target:
-    args.target = True
-  if args.target and not args.tmpdir:
-    logging.error("Need a tmpdir.")
-    return 1
-  if args.target and not args.debugfs:
-    logging.error("Need debugfs.")
-    return 1
-
-  try:
-    apex_provider = TargetApexProvider(args.apex, args.tmpdir, args.debugfs)
-  except:
-    logging.error('Failed to create provider')
-    return 1
-
-  checkers = []
-  if args.host:
-    logging.error('host checking not yet supported')
-    return 1
-
-  checkers.append(ReleaseChecker(apex_provider))
-  if args.debug:
-    checkers.append(DebugChecker(apex_provider))
-
-  failed = False
-  for checker in checkers:
-    logging.info('%s...', checker)
-    checker.run()
-    if checker.error_count() > 0:
-      logging.error('%s FAILED', checker)
-      failed = True
-    else:
-      logging.info('%s SUCCEEDED', checker)
-
-  return 1 if failed else 0
-
-def artApexTestDefault(parser):
-  if not 'ANDROID_PRODUCT_OUT' in os.environ:
-    logging.error('No-argument use requires ANDROID_PRODUCT_OUT')
-    sys.exit(1)
-  product_out = os.environ['ANDROID_PRODUCT_OUT']
-  if not 'ANDROID_HOST_OUT' in os.environ:
-    logging.error('No-argument use requires ANDROID_HOST_OUT')
-    sys.exit(1)
-  host_out = os.environ['ANDROID_HOST_OUT']
-
-  args = parser.parse_args(['dummy'])  # For consistency.
-  args.debugfs = '%s/bin/debugfs' % (host_out)
-  args.tmpdir = '.'
-  failed = False
-
-  if not os.path.exists(args.debugfs):
-    logging.error("Cannot find debugfs (default path %s). Please build it, e.g., m debugfs",
-                  args.debugfs)
-    sys.exit(1)
-
-  # TODO: Add host support
-  configs= [
-    {'name': 'com.android.runtime.release', 'target': True, 'debug': False, 'host': False},
-    {'name': 'com.android.runtime.debug', 'target': True, 'debug': True, 'host': False},
-  ]
-
-  for config in configs:
-    logging.info(config['name'])
-    # TODO: Host will need different path.
-    args.apex = '%s/system/apex/%s.apex' % (product_out, config['name'])
-    if not os.path.exists(args.apex):
-      failed = True
-      logging.error("Cannot find APEX %s. Please build it first.", args.apex)
-      continue
-    args.target = config['target']
-    args.debug = config['debug']
-    args.host = config['host']
-    exit_code = artApexTestMain(args)
-    if exit_code != 0:
-      failed = True
-
-  if failed:
-    sys.exit(1)
-
-if __name__ == "__main__":
-  parser = argparse.ArgumentParser(description='Check integrity of a Runtime APEX.')
-
-  parser.add_argument('apex', help='apex file input')
-
-  parser.add_argument('--host', help='Check as host apex', action='store_true')
-  parser.add_argument('--target', help='Check as target apex', action='store_true')
-  parser.add_argument('--debug', help='Check as debug apex', action='store_true')
-
-  parser.add_argument('--tmpdir', help='Directory for temp files')
-  parser.add_argument('--debugfs', help='Path to debugfs')
-
-  if len(sys.argv) == 1:
-    artApexTestDefault(parser)
-  else:
-    args = parser.parse_args()
-
-    if args is None:
-      sys.exit(1)
-
-    exit_code = artApexTestMain(args)
-    sys.exit(exit_code)