Use prebuilt aapt if built aapt not exist

Align the rule of using aapt with build system.

Bug: 205720152
Test: tapas MediaProviderTests ;\
      rm $(ANDROID_HOST_OUT)/bin/aapt ;\
      atest MediaProviderTests

Change-Id: Ibeec63881c4724d755f331ee8819f92399552677
diff --git a/atest/atest_utils.py b/atest/atest_utils.py
index 352f338..16eecaf 100644
--- a/atest/atest_utils.py
+++ b/atest/atest_utils.py
@@ -30,6 +30,7 @@
 import logging
 import os
 import pickle
+import platform
 import re
 import shutil
 import subprocess
@@ -39,6 +40,7 @@
 import zipfile
 
 from multiprocessing import Process
+from pathlib import Path
 
 import xml.etree.ElementTree as ET
 
@@ -1594,3 +1596,12 @@
     proc = Process(target=func, *args, **kwargs)
     proc.start()
     return proc
+
+def get_prebuilt_sdk_tools_dir():
+    """Get the path for the prebuilt sdk tools root dir.
+
+    Returns: The absolute path of prebuilt sdk tools directory.
+    """
+    build_top = Path(os.environ.get(constants.ANDROID_BUILD_TOP, ''))
+    return build_top.joinpath(
+        'prebuilts/sdk/tools/', str(platform.system()).lower(), 'bin')
diff --git a/atest/test_runners/atest_tf_test_runner.py b/atest/test_runners/atest_tf_test_runner.py
index f1932c9..7bc1c73 100644
--- a/atest/test_runners/atest_tf_test_runner.py
+++ b/atest/test_runners/atest_tf_test_runner.py
@@ -27,6 +27,7 @@
 import socket
 
 from functools import partial
+from pathlib import Path
 
 import atest_error
 import atest_utils
@@ -51,7 +52,8 @@
 # EVENT_RE has groups for the name and the data. "." does not match \n.
 EVENT_RE = re.compile(r'\n*(?P<event_name>[A-Z_]+) (?P<json_data>{.*})(?=\n|.)*')
 
-EXEC_DEPENDENCIES = ('adb', 'aapt', 'fastboot')
+# Remove aapt from build dependency, use prebuilt version instead.
+EXEC_DEPENDENCIES = ('adb', 'fastboot')
 
 TRADEFED_EXIT_MSG = 'TradeFed subprocess exited early with exit code=%s.'
 
@@ -59,6 +61,9 @@
 
 _INTEGRATION_FINDERS = frozenset(['', 'INTEGRATION', 'INTEGRATION_FILE_PATH'])
 
+# AAPT binary name
+_AAPT = 'aapt'
+
 class TradeFedExitError(Exception):
     """Raised when TradeFed exists before test run has finished."""
 
@@ -91,7 +96,8 @@
         if not os.path.exists(self.log_path):
             os.makedirs(self.log_path)
         log_args = {'log_path': self.log_path,
-                    'proto_path': os.path.join(self.results_dir, constants.ATEST_TEST_RECORD_PROTO)}
+                    'proto_path': os.path.join(
+                        self.results_dir, constants.ATEST_TEST_RECORD_PROTO)}
         self.run_cmd_dict = {'env': self._get_ld_library_path(),
                              'exe': self.EXECUTABLE,
                              'template': self._TF_TEMPLATE,
@@ -379,6 +385,16 @@
                 continue
             filtered_paths.append(path)
         env_vars['PYTHONPATH'] = ':'.join(filtered_paths)
+
+        # Use prebuilt aapt if there's no aapt under android system path which
+        # is aligned with build system.
+        # https://android.googlesource.com/platform/build/+/master/core/config.mk#529
+        if self._is_missing_exec(_AAPT):
+            prebuilt_aapt = Path.joinpath(
+                atest_utils.get_prebuilt_sdk_tools_dir(), _AAPT)
+            if os.path.exists(prebuilt_aapt):
+                env_vars['PATH'] = (str(prebuilt_aapt.parent) + ':'
+                                    + env_vars['PATH'])
         return env_vars
 
     # pylint: disable=unnecessary-pass
@@ -407,7 +423,7 @@
             return True
         # TODO: Check if there is a clever way to determine if system adb is
         # good enough.
-        root_dir = os.environ.get(constants.ANDROID_BUILD_TOP)
+        root_dir = os.environ.get(constants.ANDROID_BUILD_TOP, '')
         return os.path.commonprefix([output, root_dir]) != root_dir
 
     def get_test_runner_build_reqs(self):
diff --git a/atest/test_runners/atest_tf_test_runner_unittest.py b/atest/test_runners/atest_tf_test_runner_unittest.py
index 650d18a..ae20040 100755
--- a/atest/test_runners/atest_tf_test_runner_unittest.py
+++ b/atest/test_runners/atest_tf_test_runner_unittest.py
@@ -25,6 +25,7 @@
 import json
 
 from io import StringIO
+from pathlib import Path
 from unittest import mock
 
 import atest_utils
@@ -806,5 +807,33 @@
             {constants.CUSTOM_ARGS: [constants.TF_MODULE_PARAMETER]})
         self.assertTrue(constants.TF_ENABLE_PARAMETERIZED_MODULES in args)
 
+    @mock.patch('atest_utils.get_prebuilt_sdk_tools_dir')
+    @mock.patch.object(atf_tr.AtestTradefedTestRunner,
+                       '_is_missing_exec', return_value=False)
+    def test_generate_env_vars_aapt_already_in_system_path(
+        self, _mock_is_missing_exec, mock_prebuilt_sdk_dir):
+        """Test generate_env_vars if aapt already in system path."""
+        prebuilt_sdk_dir = Path('/my/test/sdk/dir')
+        mock_prebuilt_sdk_dir.return_value = prebuilt_sdk_dir
+
+        env_vars = self.tr.generate_env_vars(extra_args={})
+
+        self.assertFalse(
+            str(prebuilt_sdk_dir) + ':' in env_vars.get('PATH', ''))
+
+    @mock.patch('os.path.exists', return_value=True)
+    @mock.patch('atest_utils.get_prebuilt_sdk_tools_dir')
+    @mock.patch.object(atf_tr.AtestTradefedTestRunner,
+                       '_is_missing_exec', return_value=True)
+    def test_generate_env_vars_aapt_not_in_system_path(
+        self, _mock_is_missing_exec, mock_prebuilt_sdk_dir, _mock_exist):
+        """Test generate_env_vars if aapt not in system path."""
+        prebuilt_sdk_dir = Path('/my/test/sdk/dir')
+        mock_prebuilt_sdk_dir.return_value = prebuilt_sdk_dir
+
+        env_vars = self.tr.generate_env_vars(extra_args={})
+
+        self.assertTrue(str(prebuilt_sdk_dir) + ':' in env_vars.get('PATH', ''))
+
 if __name__ == '__main__':
     unittest.main()