Merge "AdbWinApi: switch to Android.bp."
diff --git a/vndk/snapshot/check_gpl_license.py b/vndk/snapshot/check_gpl_license.py
index 228888e..aa45350 100644
--- a/vndk/snapshot/check_gpl_license.py
+++ b/vndk/snapshot/check_gpl_license.py
@@ -30,8 +30,8 @@
     Makes sure that the current source tree have the sources for all GPL
     prebuilt libraries in a specified VNDK snapshot version.
     """
-    MANIFEST_XML = 'manifest.xml'
-    MODULE_PATHS_TXT = 'module_paths.txt'
+    MANIFEST_XML = utils.MANIFEST_FILE_NAME
+    MODULE_PATHS_TXT = utils.MODULE_PATHS_FILE_NAME
 
     def __init__(self, install_dir, android_build_top):
         """GPLChecker constructor.
@@ -43,12 +43,14 @@
         """
         self._android_build_top = android_build_top
         self._install_dir = install_dir
-        self._manifest_file = os.path.join(install_dir, self.MANIFEST_XML)
-        self._notice_files_dir = os.path.join(install_dir, 'NOTICE_FILES')
+        self._manifest_file = os.path.join(install_dir,
+                                           utils.MANIFEST_FILE_PATH)
+        self._notice_files_dir = os.path.join(install_dir,
+                                              utils.NOTICE_FILES_DIR_PATH)
 
         if not os.path.isfile(self._manifest_file):
-            raise RuntimeError('{manifest} not found in {install_dir}'.format(
-                manifest=self.MANIFEST_XML, install_dir=install_dir))
+            raise RuntimeError('{manifest} not found at {manifest_file}'.format(
+                manifest=self.MANIFEST_XML, manifest_file=self._manifest_file))
 
     def _parse_module_paths(self):
         """Parses the module_path.txt files into a dictionary,
diff --git a/vndk/snapshot/gen_buildfiles.py b/vndk/snapshot/gen_buildfiles.py
index 71a4b8a..8d7cce7 100644
--- a/vndk/snapshot/gen_buildfiles.py
+++ b/vndk/snapshot/gen_buildfiles.py
@@ -23,15 +23,39 @@
 
 
 class GenBuildFile(object):
-    """Generates Android.mk and Android.bp for prebuilts/vndk/v{version}."""
+    """Generates Android.mk and Android.bp for VNDK snapshot.
 
+    VNDK snapshot directory structure under prebuilts/vndk/v{version}:
+        {SNAPSHOT_VARIANT}/
+            Android.bp
+            arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/
+                shared/
+                    vndk-core/
+                        (VNDK-core libraries, e.g. libbinder.so)
+                    vndk-sp/
+                        (VNDK-SP libraries, e.g. libc++.so)
+            arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/
+                shared/
+                    vndk-core/
+                        (VNDK-core libraries, e.g. libbinder.so)
+                    vndk-sp/
+                        (VNDK-SP libraries, e.g. libc++.so)
+            configs/
+                (various *.txt configuration files, e.g. ld.config.*.txt)
+        ... (other {SNAPSHOT_VARIANT}/ directories)
+        common/
+            Android.mk
+            manifest.xml
+            NOTICE_FILES/
+                (license files, e.g. libfoo.so.txt)
+    """
     INDENT = '    '
-    ETC_LIST = ['ld.config.txt', 'llndk.libraries.txt', 'vndksp.libraries.txt']
+    ETC_MODULES = [
+        'ld.config.txt', 'llndk.libraries.txt', 'vndksp.libraries.txt'
+    ]
 
     # TODO(b/70312118): Parse from soong build system
-    RELATIVE_INSTALL_PATHS = {
-        'android.hidl.memory@1.0-impl.so': 'hw'
-    }
+    RELATIVE_INSTALL_PATHS = {'android.hidl.memory@1.0-impl.so': 'hw'}
 
     def __init__(self, install_dir, vndk_version):
         """GenBuildFile constructor.
@@ -43,35 +67,49 @@
         """
         self._install_dir = install_dir
         self._vndk_version = vndk_version
-        self._mkfile = os.path.join(install_dir, 'Android.mk')
-        self._bpfile = os.path.join(install_dir, 'Android.bp')
+        self._etc_paths = self._get_etc_paths()
+        self._snapshot_variants = utils.get_snapshot_variants(install_dir)
+        self._mkfile = os.path.join(install_dir, utils.ANDROID_MK_PATH)
         self._vndk_core = self._parse_lib_list('vndkcore.libraries.txt')
-        self._vndk_sp = self._parse_lib_list('vndksp.libraries.txt')
+        self._vndk_sp = self._parse_lib_list(
+            os.path.basename(self._etc_paths['vndksp.libraries.txt']))
         self._vndk_private = self._parse_lib_list('vndkprivate.libraries.txt')
 
+    def _get_etc_paths(self):
+        """Returns a map of relative file paths for each ETC module."""
+
+        etc_paths = dict()
+        for etc_module in self.ETC_MODULES:
+            etc_pattern = '{}*'.format(os.path.splitext(etc_module)[0])
+            etc_path = glob.glob(
+                os.path.join(self._install_dir, utils.CONFIG_DIR_PATH_PATTERN,
+                             etc_pattern))[0]
+            rel_etc_path = etc_path.replace(self._install_dir, '')[1:]
+            etc_paths[etc_module] = rel_etc_path
+        return etc_paths
+
     def _parse_lib_list(self, txt_filename):
-        """Returns a sorted union list of libraries found in provided filenames.
+        """Returns a map of VNDK library lists per VNDK snapshot variant.
 
         Args:
-          txt_filename: string, file name in VNDK snapshot
-        """
-        prebuilt_list = []
-        txts = utils.find(self._install_dir, [txt_filename])
-        for txt in txts:
-            path_to_txt = os.path.join(self._install_dir, txt)
-            with open(path_to_txt, 'r') as f:
-                prebuilts = f.read().strip().split('\n')
-                for prebuilt in prebuilts:
-                    if prebuilt not in prebuilt_list:
-                        prebuilt_list.append(prebuilt)
+          txt_filename: string, name of snapshot config file
 
-        return sorted(prebuilt_list)
+        Returns:
+          dict, e.g. {'arm64': ['libfoo.so', 'libbar.so', ...], ...}
+        """
+        lib_map = dict()
+        for txt_path in utils.find(self._install_dir, [txt_filename]):
+            variant = utils.variant_from_path(txt_path)
+            abs_path_of_txt = os.path.join(self._install_dir, txt_path)
+            with open(abs_path_of_txt, 'r') as f:
+                lib_map[variant] = f.read().strip().split('\n')
+        return lib_map
 
     def generate_android_mk(self):
         """Autogenerates Android.mk."""
 
         etc_buildrules = []
-        for prebuilt in self.ETC_LIST:
+        for prebuilt in self.ETC_MODULES:
             etc_buildrules.append(self._gen_etc_prebuilt(prebuilt))
 
         with open(self._mkfile, 'w') as mkfile:
@@ -83,43 +121,47 @@
             mkfile.write('\n')
 
     def generate_android_bp(self):
-        """Autogenerates Android.bp."""
+        """Autogenerates Android.bp file for each VNDK snapshot variant."""
 
-        vndk_core_buildrules = self._gen_vndk_shared_prebuilts(
-            self._vndk_core, False)
-        vndk_sp_buildrules = self._gen_vndk_shared_prebuilts(
-            self._vndk_sp, True)
+        for variant in self._snapshot_variants:
+            bpfile = os.path.join(self._install_dir, variant, 'Android.bp')
+            vndk_core_buildrules = self._gen_vndk_shared_prebuilts(
+                self._vndk_core[variant], variant, False)
+            vndk_sp_buildrules = self._gen_vndk_shared_prebuilts(
+                self._vndk_sp[variant], variant, True)
 
-        with open(self._bpfile, 'w') as bpfile:
-            bpfile.write(self._gen_autogen_msg('/'))
-            bpfile.write('\n')
-            bpfile.write(self._gen_bp_phony())
-            bpfile.write('\n')
-            bpfile.write('\n'.join(vndk_core_buildrules))
-            bpfile.write('\n'.join(vndk_sp_buildrules))
+            with open(bpfile, 'w') as bpfile:
+                bpfile.write(self._gen_autogen_msg('/'))
+                bpfile.write('\n')
+                bpfile.write(self._gen_bp_phony(variant))
+                bpfile.write('\n')
+                bpfile.write('\n'.join(vndk_core_buildrules))
+                bpfile.write('\n'.join(vndk_sp_buildrules))
 
     def _gen_autogen_msg(self, comment_char):
         return ('{0}{0} THIS FILE IS AUTOGENERATED BY '
                 'development/vndk/snapshot/gen_buildfiles.py\n'
                 '{0}{0} DO NOT EDIT\n'.format(comment_char))
 
-    def _get_versioned_name(self, prebuilt, is_etc):
+    def _get_versioned_name(self, prebuilt, variant, is_etc):
         """Returns the VNDK version-specific module name for a given prebuilt.
 
         The VNDK version-specific module name is defined as follows:
-        For a VNDK shared library: "libfoo.so" -> "libfoo.vndk.{version}.vendor"
-        For an ETC text file: "foo.txt" -> "foo.{version}.txt"
+        For a VNDK shared lib: 'libfoo.so'
+                            -> 'libfoo.vndk.{version}.{variant}.vendor'
+        For an ETC module: 'foo.txt' -> 'foo.{version}.txt'
 
         Args:
           prebuilt: string, name of the prebuilt object
+          variant: string, VNDK snapshot variant (e.g. 'arm64')
           is_etc: bool, True if the LOCAL_MODULE_CLASS of prebuilt is 'ETC'
         """
         name, ext = os.path.splitext(prebuilt)
         if is_etc:
             versioned_name = '{}.{}{}'.format(name, self._vndk_version, ext)
         else:
-            versioned_name = '{}.vndk.{}.vendor'.format(
-                name, self._vndk_version)
+            versioned_name = '{}.vndk.{}.{}.vendor'.format(
+                name, self._vndk_version, variant)
 
         return versioned_name
 
@@ -129,36 +171,37 @@
         Args:
           prebuilt: string, name of ETC prebuilt object
         """
-        etc_pattern = 'arch-*/configs/{}*'.format(os.path.splitext(prebuilt)[0])
-        etc_path = glob.glob(etc_pattern)[0]
+        etc_path = self._etc_paths[prebuilt]
         etc_sub_path = etc_path[etc_path.index('/') + 1:]
 
-        return (
-            '#######################################\n'
-            '# {prebuilt}\n'
-            'include $(CLEAR_VARS)\n'
-            'LOCAL_MODULE := {versioned_name}\n'
-            'LOCAL_SRC_FILES := arch-$(TARGET_ARCH)-$(TARGET_ARCH_VARIANT)/'
-            '{etc_sub_path}\n'
-            'LOCAL_MODULE_CLASS := ETC\n'
-            'LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)\n'
-            'LOCAL_MODULE_STEM := $(LOCAL_MODULE)\n'
-            'include $(BUILD_PREBUILT)\n'.format(
-                prebuilt=prebuilt,
-                versioned_name=self._get_versioned_name(prebuilt, True),
-                etc_sub_path=etc_sub_path))
+        return ('#######################################\n'
+                '# {prebuilt}\n'
+                'include $(CLEAR_VARS)\n'
+                'LOCAL_MODULE := {versioned_name}\n'
+                'LOCAL_SRC_FILES := ../$(TARGET_ARCH)/{etc_sub_path}\n'
+                'LOCAL_MODULE_CLASS := ETC\n'
+                'LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)\n'
+                'LOCAL_MODULE_STEM := $(LOCAL_MODULE)\n'
+                'include $(BUILD_PREBUILT)\n'.format(
+                    prebuilt=prebuilt,
+                    versioned_name=self._get_versioned_name(
+                        prebuilt, None, True),
+                    etc_sub_path=etc_sub_path))
 
-    def _gen_bp_phony(self):
-        """Generates build rule for phony package 'vndk_v{version}'."""
+    def _gen_bp_phony(self, variant):
+        """Generates build rule for phony package 'vndk_v{ver}_{variant}'.
 
+        Args:
+          variant: string, VNDK snapshot variant (e.g. 'arm64')
+        """
         required = []
+        for prebuilts in (self._vndk_core[variant], self._vndk_sp[variant]):
+            for prebuilt in prebuilts:
+                required.append(
+                    self._get_versioned_name(prebuilt, variant, False))
 
-        for prebuilts_list in (self._vndk_core, self._vndk_sp):
-            for prebuilt in prebuilts_list:
-                required.append(self._get_versioned_name(prebuilt, False))
-
-        for prebuilt in self.ETC_LIST:
-            required.append(self._get_versioned_name(prebuilt, True))
+        for prebuilt in self.ETC_MODULES:
+            required.append(self._get_versioned_name(prebuilt, None, True))
 
         required_str = ['"{}",'.format(prebuilt) for prebuilt in required]
         required_formatted = '\n{ind}{ind}'.format(
@@ -170,33 +213,37 @@
                                   required_formatted=required_formatted))
 
         return ('phony {{\n'
-                '{ind}name: "vndk_v{ver}",\n'
+                '{ind}name: "vndk_v{ver}_{variant}",\n'
                 '{required_buildrule}'
                 '}}\n'.format(
                     ind=self.INDENT,
                     ver=self._vndk_version,
+                    variant=variant,
                     required_buildrule=required_buildrule))
 
-    def _gen_vndk_shared_prebuilts(self, prebuilts, is_vndk_sp):
+    def _gen_vndk_shared_prebuilts(self, prebuilts, variant, is_vndk_sp):
         """Returns list of build rules for given prebuilts.
 
         Args:
           prebuilts: list of VNDK shared prebuilts
+          variant: string, VNDK snapshot variant (e.g. 'arm64')
           is_vndk_sp: bool, True if prebuilts are VNDK_SP libs
         """
         build_rules = []
         for prebuilt in prebuilts:
             build_rules.append(
-                self._gen_vndk_shared_prebuilt(prebuilt, is_vndk_sp))
+                self._gen_vndk_shared_prebuilt(prebuilt, variant, is_vndk_sp))
         return build_rules
 
-    def _gen_vndk_shared_prebuilt(self, prebuilt, is_vndk_sp):
+    def _gen_vndk_shared_prebuilt(self, prebuilt, variant, is_vndk_sp):
         """Returns build rule for given prebuilt.
 
         Args:
           prebuilt: string, name of prebuilt object
+          variant: string, VNDK snapshot variant (e.g. 'arm64')
           is_vndk_sp: bool, True if prebuilt is a VNDK_SP lib
         """
+
         def get_notice_file(prebuilt):
             """Returns build rule for notice file (attribute 'notice').
 
@@ -205,13 +252,14 @@
             """
             notice = ''
             notice_file_name = '{}.txt'.format(prebuilt)
-            notices_dir = os.path.join(self._install_dir, 'NOTICE_FILES')
+            notices_dir = os.path.join(self._install_dir,
+                                       utils.NOTICE_FILES_DIR_PATH)
             notice_files = utils.find(notices_dir, [notice_file_name])
             if len(notice_files) > 0:
                 notice = '{ind}notice: "{notice_file_path}",\n'.format(
                     ind=self.INDENT,
                     notice_file_path=os.path.join(
-                        'NOTICE_FILES', notice_files[0]))
+                        '..', utils.NOTICE_FILES_DIR_PATH, notice_files[0]))
             return notice
 
         def get_rel_install_path(prebuilt):
@@ -227,37 +275,40 @@
                                      .format(ind=self.INDENT, path=path))
             return rel_install_path
 
-        def get_arch_srcs(prebuilt):
+        def get_arch_srcs(prebuilt, variant):
             """Returns build rule for arch specific srcs.
 
             e.g.,
-            arch: {
-                arm: {
-                    srcs: ["..."]
-                },
-                arm64: {
-
-                },
-                ...
-            }
+                arch: {
+                    arm: {
+                        srcs: ["..."]
+                    },
+                    arm64: {
+                        srcs: ["..."]
+                    },
+                }
 
             Args:
               prebuilt: string, name of prebuilt object
+              variant: string, VNDK snapshot variant (e.g. 'arm64')
             """
             arch_srcs = '{ind}arch: {{\n'.format(ind=self.INDENT)
-            src_paths = utils.find(self._install_dir, [prebuilt])
+            variant_path = os.path.join(self._install_dir, variant)
+            src_paths = utils.find(variant_path, [prebuilt])
             for src in sorted(src_paths):
-                arch_srcs += ('{ind}{ind}{arch}: {{\n'
-                              '{ind}{ind}{ind}srcs: ["{src}"],\n'
-                              '{ind}{ind}}},\n'.format(
-                                  ind=self.INDENT,
-                                  arch=utils.arch_from_path(src),
-                                  src=src))
+                arch_srcs += (
+                    '{ind}{ind}{arch}: {{\n'
+                    '{ind}{ind}{ind}srcs: ["{src}"],\n'
+                    '{ind}{ind}}},\n'.format(
+                        ind=self.INDENT,
+                        arch=utils.arch_from_path(os.path.join(variant, src)),
+                        src=src))
             arch_srcs += '{ind}}},\n'.format(ind=self.INDENT)
             return arch_srcs
 
         name = os.path.splitext(prebuilt)[0]
-        vendor_available = 'false' if prebuilt in self._vndk_private else 'true'
+        vendor_available = str(
+            prebuilt not in self._vndk_private[variant]).lower()
         if is_vndk_sp:
             vndk_sp = '{ind}{ind}support_system_process: true,\n'.format(
                 ind=self.INDENT)
@@ -265,11 +316,12 @@
             vndk_sp = ''
         notice = get_notice_file(prebuilt)
         rel_install_path = get_rel_install_path(prebuilt)
-        arch_srcs = get_arch_srcs(prebuilt)
+        arch_srcs = get_arch_srcs(prebuilt, variant)
 
         return ('vndk_prebuilt_shared {{\n'
                 '{ind}name: "{name}",\n'
                 '{ind}version: "{ver}",\n'
+                '{ind}target_arch: "{target_arch}",\n'
                 '{ind}vendor_available: {vendor_available},\n'
                 '{ind}vndk: {{\n'
                 '{ind}{ind}enabled: true,\n'
@@ -283,6 +335,7 @@
                     name=name,
                     ver=self._vndk_version,
                     vendor_available=vendor_available,
+                    target_arch=variant,
                     vndk_sp=vndk_sp,
                     notice=notice,
                     rel_install_path=rel_install_path,
@@ -296,8 +349,8 @@
       prebuilts/vndk/v{version}.
     """
     ANDROID_BUILD_TOP = utils.get_android_build_top()
-    PREBUILTS_VNDK_DIR = utils.join_realpath(
-        ANDROID_BUILD_TOP, 'prebuilts/vndk')
+    PREBUILTS_VNDK_DIR = utils.join_realpath(ANDROID_BUILD_TOP,
+                                             'prebuilts/vndk')
 
     vndk_version = 27  # set appropriately
     install_dir = os.path.join(PREBUILTS_VNDK_DIR, 'v{}'.format(vndk_version))
diff --git a/vndk/snapshot/test.sh b/vndk/snapshot/test.sh
index 35449c2..7938d05 100755
--- a/vndk/snapshot/test.sh
+++ b/vndk/snapshot/test.sh
@@ -22,11 +22,11 @@
 #   First, generate VNDK snapshots with development/vndk/snapshot/build.sh or
 #   fetch VNDK snapshot build artifacts to $DIST_DIR, then run this script.
 
-set -euo pipefail
+set -eo pipefail
 
 if [ "$#" -ne 1 ]; then
-    echo "Usage: \"$0 all\" to test all four arch snapshots at once."
-    echo "Usage: \"$0 TARGET_ARCH\" to test for a VNDK snapshot of a specific arch."
+    echo "Usage: \"$0 all\" to test all four VNDK snapshot variants at once."
+    echo "Usage: \"$0 TARGET_ARCH\" to test a VNDK snapshot of a specific arch."
     exit 1
 fi
 
@@ -50,6 +50,10 @@
     fi
 fi
 
+# Get PLATFORM_VNDK_VERSION
+source "$ANDROID_BUILD_TOP/build/envsetup.sh" >/dev/null
+PLATFORM_VNDK_VERSION=`get_build_var PLATFORM_VNDK_VERSION`
+
 SNAPSHOT_TOP=$DIST_DIR/android-vndk-snapshot
 SNAPSHOT_TEMPFILE=$DIST_DIR/snapshot_libs.txt
 SYSTEM_TEMPFILE=$DIST_DIR/system_libs.txt
@@ -60,7 +64,6 @@
 FAIL="${RED}::: FAIL :::${NC}"
 
 
-
 function remove_unzipped_snapshot {
     if [ -d $SNAPSHOT_TOP ]; then
         echo "Removing $SNAPSHOT_TOP"
@@ -76,50 +79,78 @@
 #
 # Arguments:
 #   $1: vndk_type: string, one of [vndk-core, vndk-sp]
-#   $2: arch: string, one of [arm, arm64, x86, x86_64]
+#   $2: target_arch: string, one of [arm, arm64, x86, x86_64]
 #######################################
 function compare_vndk_libs() {
     local vndk_type=$1
-    local arch=$2
+    local target_arch=$2
+    local target_arch_2nd=''
     local product
     local bitness
     local snapshot_dir
+    local snapshot_dir_2nd
+    local vndk_dir_suffix
     local system_vndk_dir
-    local system_dir
+    local system_lib_dir
+    local system_lib_dir_2nd
 
-    if [[ $arch == 'arm64' ]]; then
+    if [[ $target_arch == 'arm64' ]]; then
         product='generic_arm64_ab'
-    elif [[ $arch == 'arm' ]]; then
+        target_arch_2nd='arm'
+    elif [[ $target_arch == 'arm' ]]; then
         product='generic_arm_ab'
-    elif [[ $arch == 'x86_64' ]]; then
+    elif [[ $target_arch == 'x86_64' ]]; then
         product='generic_x86_64_ab'
-    elif [[ $arch == 'x86' ]]; then
+        target_arch_2nd='x86'
+    elif [[ $target_arch == 'x86' ]]; then
         product='generic_x86_ab'
     fi
 
-    if [[ ${arch:-2:length} =~ '64' ]]; then
+    if [[ ${target_arch:-2:length} =~ '64' ]]; then
         bitness='64'
     else
         bitness=''
     fi
 
-    snapshot_dir=$SNAPSHOT_TOP/arch-$arch*/shared/$vndk_type
-
-    if [[ $vndk_type == 'vndk-core' ]]; then
-        system_vndk_dir='vndk'
+    if [[ -z $PLATFORM_VNDK_VERSION ]]; then
+        vndk_dir_suffix=""
     else
-        system_vndk_dir='vndk-sp'
+        vndk_dir_suffix="-$PLATFORM_VNDK_VERSION"
     fi
 
-    system_dir=$ANDROID_BUILD_TOP/out/target/product/$product/system/lib$bitness/$system_vndk_dir
+    if [[ $vndk_type == 'vndk-core' ]]; then
+        system_vndk_dir="vndk${vndk_dir_suffix}"
+    else
+        system_vndk_dir="vndk-sp${vndk_dir_suffix}"
+    fi
 
-    ls -1 $snapshot_dir > $SNAPSHOT_TEMPFILE
-    find $system_dir -type f | xargs -n 1 -I file bash -c "basename file" | sort > $SYSTEM_TEMPFILE
+    function diff_vndk_dirs() {
+        local snapshot=$1
+        local system=$2
+        local local_module_target_arch=$3
 
-    echo "Comparing libs for VNDK=$vndk_type and ARCH=$arch"
-    (diff --old-line-format="Only found in VNDK snapshot: %L" --new-line-format="Only found in system/lib*: %L" \
-      --unchanged-line-format="" $SNAPSHOT_TEMPFILE $SYSTEM_TEMPFILE && echo $PASS) \
-    || (echo -e $FAIL; exit 1)
+        ls -1 $snapshot > $SNAPSHOT_TEMPFILE
+        find $system -type f | xargs -n 1 -I file bash -c "basename file" | sort > $SYSTEM_TEMPFILE
+
+        echo "Comparing libs for VNDK=$vndk_type, SNAPSHOT_VARIANT=$target_arch, ARCH=$local_module_target_arch"
+        echo "Snapshot dir: $snapshot"
+        echo "System dir: $system"
+        (diff --old-line-format="Only found in VNDK snapshot: %L" \
+              --new-line-format="Only found in /system/lib*: %L" \
+              --unchanged-line-format="" \
+              $SNAPSHOT_TEMPFILE $SYSTEM_TEMPFILE && echo $PASS) \
+        || (echo -e $FAIL; exit 1)
+    }
+
+    snapshot_dir=$SNAPSHOT_TOP/$target_arch/arch-$target_arch-*/shared/$vndk_type
+    system_lib_dir=$ANDROID_BUILD_TOP/out/target/product/$product/system/lib$bitness/$system_vndk_dir
+    diff_vndk_dirs $snapshot_dir $system_lib_dir $target_arch
+
+    if [[ -n $target_arch_2nd ]]; then
+        snapshot_dir_2nd=$SNAPSHOT_TOP/$target_arch/arch-$target_arch_2nd-*/shared/$vndk_type
+        system_lib_dir_2nd=$ANDROID_BUILD_TOP/out/target/product/$product/system/lib/$system_vndk_dir
+        diff_vndk_dirs $snapshot_dir_2nd $system_lib_dir_2nd $target_arch_2nd
+    fi
 }
 
 
@@ -132,24 +163,32 @@
 function run_test_cases() {
     local arch=$1
     local snapshot_zip=$DIST_DIR/android-vndk-$arch.zip
+    local snapshot_variant_top=$SNAPSHOT_TOP/$arch
 
     echo "[Setup] Unzipping \"android-vndk-$arch.zip\""
     unzip -q $snapshot_zip -d $SNAPSHOT_TOP
 
-    echo "[Test] Comparing VNDK-core and VNDK-SP libs in snapshot vs system/lib*"
+    echo "[Test] Comparing VNDK-core and VNDK-SP libs in snapshot vs /system/lib*"
     compare_vndk_libs 'vndk-core' $arch
     compare_vndk_libs 'vndk-sp' $arch
 
     echo "[Test] Checking required config files are present"
+
+    if [[ -z $PLATFORM_VNDK_VERSION ]]; then
+        config_file_suffix=""
+    else
+        config_file_suffix=".$PLATFORM_VNDK_VERSION"
+    fi
+
     config_files=(
-        'ld.config.txt'
-        'llndk.libraries.txt'
-        'module_paths.txt'
-        'vndkcore.libraries.txt'
-        'vndkprivate.libraries.txt'
-        'vndksp.libraries.txt')
+        "ld.config$config_file_suffix.txt"
+        "llndk.libraries$config_file_suffix.txt"
+        "vndksp.libraries$config_file_suffix.txt"
+        "vndkcore.libraries.txt"
+        "vndkprivate.libraries.txt"
+        "module_paths.txt")
     for config_file in "${config_files[@]}"; do
-        config_file_abs_path=$SNAPSHOT_TOP/arch-$arch*/configs/$config_file
+        config_file_abs_path=$snapshot_variant_top/configs/$config_file
         if [ ! -e $config_file_abs_path ]; then
             echo -e "$FAIL The file \"$config_file_abs_path\" was not found in snapshot."
             exit 1
@@ -161,11 +200,9 @@
     echo "[Test] Checking directory structure of snapshot"
     directories=(
         'configs/'
-        'NOTICE_FILES/'
-        'shared/vndk-core/'
-        'shared/vndk-sp/')
+        'NOTICE_FILES/')
     for sub_dir in "${directories[@]}"; do
-        dir_abs_path=$SNAPSHOT_TOP/arch-$arch*/$sub_dir
+        dir_abs_path=$snapshot_variant_top/$sub_dir
         if [ ! -d $dir_abs_path ]; then
             echo -e "$FAIL The directory \"$dir_abs_path\" was not found in snapshot."
             exit 1
diff --git a/vndk/snapshot/update.py b/vndk/snapshot/update.py
index 7f74eb0..4ba6d03 100644
--- a/vndk/snapshot/update.py
+++ b/vndk/snapshot/update.py
@@ -100,12 +100,13 @@
             fetch_artifact(branch, build, artifact_pattern)
 
             manifest_pattern = 'manifest_{}.xml'.format(build)
-            manifest_name = 'manifest.xml'
+            manifest_name = utils.MANIFEST_FILE_NAME
             logger().info(
                 'Fetching {file} from {branch} (bid: {build})'.format(
                     file=manifest_pattern, branch=branch, build=build))
             fetch_artifact(branch, build, manifest_pattern, manifest_name)
-            shutil.move(manifest_name, install_dir)
+            shutil.move(manifest_name,
+                        os.path.join(install_dir, utils.COMMON_DIR_PATH))
 
             os.chdir(install_dir)
         else:
@@ -128,25 +129,23 @@
             shutil.rmtree(tempdir)
 
 
-def gather_notice_files():
-    """Gathers all NOTICE files to a new NOTICE_FILES directory.
+def gather_notice_files(install_dir):
+    """Gathers all NOTICE files to a common NOTICE_FILES directory."""
 
-    Create a new NOTICE_FILES directory under install_dir and copy to it
-    all NOTICE files in arch-*/NOTICE_FILES.
-    """
-    notices_dir_name = 'NOTICE_FILES'
-    logger().info('Creating {} directory...'.format(notices_dir_name))
-    os.makedirs(notices_dir_name)
-    for arch_dir in glob.glob('arch-*'):
-        notices_dir_per_arch = os.path.join(arch_dir, notices_dir_name)
-        if os.path.isdir(notices_dir_per_arch):
+    common_notices_dir = utils.NOTICE_FILES_DIR_PATH
+    logger().info('Creating {} directory...'.format(common_notices_dir))
+    os.makedirs(common_notices_dir)
+    for variant in utils.get_snapshot_variants(install_dir):
+        notices_dir_per_variant = os.path.join(variant,
+                                               utils.NOTICE_FILES_DIR_NAME)
+        if os.path.isdir(notices_dir_per_variant):
             for notice_file in glob.glob(
-                    '{}/*.txt'.format(notices_dir_per_arch)):
+                    '{}/*.txt'.format(notices_dir_per_variant)):
                 if not os.path.isfile(
-                        os.path.join(notices_dir_name,
+                        os.path.join(common_notices_dir,
                                      os.path.basename(notice_file))):
-                    shutil.copy(notice_file, notices_dir_name)
-            shutil.rmtree(notices_dir_per_arch)
+                    shutil.copy(notice_file, common_notices_dir)
+            shutil.rmtree(notices_dir_per_variant)
 
 
 def revise_ld_config_txt():
@@ -157,7 +156,8 @@
     """
     re_pattern = '(system\/\${LIB}\/vndk(?:-sp)?)([:/]|$)'
     VNDK_INSTALL_DIR_RE = re.compile(re_pattern, flags=re.MULTILINE)
-    ld_config_txt_paths = glob.glob('arch-*/configs/ld.config*')
+    ld_config_txt_paths = glob.glob(
+        os.path.join(utils.CONFIG_DIR_PATH_PATTERN, 'ld.config*'))
     for ld_config_file in ld_config_txt_paths:
         with open(ld_config_file, 'r') as file:
             revised = VNDK_INSTALL_DIR_RE.sub(r'\1${VNDK_VER}\2', file.read())
@@ -166,10 +166,10 @@
 
 
 def update_buildfiles(buildfile_generator):
-    logger().info('Updating Android.mk...')
+    logger().info('Generating Android.mk file...')
     buildfile_generator.generate_android_mk()
 
-    logger().info('Updating Android.bp...')
+    logger().info('Generating Android.bp files...')
     buildfile_generator.generate_android_bp()
 
 
@@ -250,8 +250,9 @@
         start_branch(args.build)
 
     remove_old_snapshot(install_dir)
+    os.makedirs(utils.COMMON_DIR_PATH)
     install_snapshot(args.branch, args.build, install_dir)
-    gather_notice_files()
+    gather_notice_files(install_dir)
 
     # Post-process ld.config.txt for O-MR1
     if vndk_version == '27':
diff --git a/vndk/snapshot/utils.py b/vndk/snapshot/utils.py
index b21225b..b8fff0a 100644
--- a/vndk/snapshot/utils.py
+++ b/vndk/snapshot/utils.py
@@ -16,9 +16,23 @@
 #
 """Utility functions for VNDK snapshot."""
 
+import glob
 import os
+import re
 import sys
 
+# Global Keys
+#   All paths are relative to install_dir: prebuilts/vndk/v{version}
+COMMON_DIR_NAME = 'common'
+COMMON_DIR_PATH = COMMON_DIR_NAME
+ANDROID_MK_PATH = os.path.join(COMMON_DIR_PATH, 'Android.mk')
+CONFIG_DIR_PATH_PATTERN = '*/configs'
+MANIFEST_FILE_NAME = 'manifest.xml'
+MANIFEST_FILE_PATH = os.path.join(COMMON_DIR_PATH, MANIFEST_FILE_NAME)
+MODULE_PATHS_FILE_NAME = 'module_paths.txt'
+NOTICE_FILES_DIR_NAME = 'NOTICE_FILES'
+NOTICE_FILES_DIR_PATH = os.path.join(COMMON_DIR_PATH, NOTICE_FILES_DIR_NAME)
+
 
 def get_android_build_top():
     ANDROID_BUILD_TOP = os.getenv('ANDROID_BUILD_TOP')
@@ -46,16 +60,42 @@
     return _get_dir_from_env('DIST_DIR', join_realpath(out_dir, 'dist'))
 
 
+def get_snapshot_variants(install_dir):
+    """Returns a list of VNDK snapshot variants under install_dir.
+
+    Args:
+      install_dir: string, absolute path of prebuilts/vndk/v{version}
+    """
+    variants = []
+    for file in glob.glob('{}/*'.format(install_dir)):
+        basename = os.path.basename(file)
+        if os.path.isdir(file) and basename != COMMON_DIR_NAME:
+            variants.append(basename)
+    return variants
+
+
 def arch_from_path(path):
-    """Extracts arch from given VNDK snapshot path.
+    """Extracts arch of prebuilts from path relative to install_dir.
 
     Args:
       path: string, path relative to prebuilts/vndk/v{version}
 
     Returns:
-      arch string, (e.g., "arm" or "arm64" or "x86" or "x86_64")
+      string, arch of prebuilt (e.g., 'arm' or 'arm64' or 'x86' or 'x86_64')
     """
-    return path.split('/')[0].split('-')[1]
+    return path.split('/')[1].split('-')[1]
+
+
+def variant_from_path(path):
+    """Extracts VNDK snapshot variant from path relative to install_dir.
+
+    Args:
+      path: string, path relative to prebuilts/vndk/v{version}
+
+    Returns:
+      string, VNDK snapshot variant (e.g. 'arm64')
+    """
+    return path.split('/')[0]
 
 
 def find(path, names):