Fix long paths on Windows

util::mkdirs iteratively creates each directory of a specified path. For
windows, Calling mkdir on only the drive letter or on the extended path
prefix (\?\\) will result in an error. Start after the long path prefix
and the drive letter.

This also changes AAPT2 to use AssetMaanager2 to retrieve symbols from
the symbol table. AssetManager2's zip library uses _wopen to open
windows files.

Bug:123251200
Test: aapt2_tests.exe
Change-Id: I26169d83b22d441485de3c49d63a6c4ed710e292
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index a212f47..af2d413 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -343,7 +343,9 @@
   assetmanager->ForEachPackage([&](const std::string& this_package_name, uint8_t package_id) {
     if (this_package_name == std_package_name) {
       map = assetmanager->GetOverlayableMapForPackage(package_id);
+      return false;
     }
+    return true;
   });
 
   if (map == nullptr) {
@@ -521,15 +523,16 @@
     return nullptr;
   }
 
-  assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) {
+  assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) -> bool {
     jstring jpackage_name = env->NewStringUTF(package_name.c_str());
     if (jpackage_name == nullptr) {
       // An exception is pending.
-      return;
+      return false;
     }
 
     env->CallVoidMethod(sparse_array, gSparseArrayOffsets.put, static_cast<jint>(package_id),
                         jpackage_name);
+    return true;
   });
   return sparse_array;
 }
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 66d8542..d7b84ff 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -356,6 +356,7 @@
 
 ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override,
                                          bool /*stop_at_first_match*/,
+                                         bool ignore_configuration,
                                          FindEntryResult* out_entry) const {
   // Might use this if density_override != 0.
   ResTable_config density_override_config;
@@ -399,7 +400,7 @@
 
   // If desired_config is the same as the set configuration, then we can use our filtered list
   // and we don't need to match the configurations, since they already matched.
-  const bool use_fast_path = desired_config == &configuration_;
+  const bool use_fast_path = !ignore_configuration && desired_config == &configuration_;
 
   for (size_t pi = 0; pi < package_count; pi++) {
     const ConfiguredPackage& loaded_package_impl = package_group.packages_[pi];
@@ -475,21 +476,23 @@
       // ResTable_config, we must copy it.
       const auto iter_end = type_spec->types + type_spec->type_count;
       for (auto iter = type_spec->types; iter != iter_end; ++iter) {
-        ResTable_config this_config;
-        this_config.copyFromDtoH((*iter)->config);
+        ResTable_config this_config{};
 
-        if (!this_config.match(*desired_config)) {
-          continue;
-        }
+        if (!ignore_configuration) {
+          this_config.copyFromDtoH((*iter)->config);
+          if (!this_config.match(*desired_config)) {
+            continue;
+          }
 
-        if (best_config == nullptr) {
-          resolution_type = Resolution::Step::Type::INITIAL;
-        } else if (this_config.isBetterThan(*best_config, desired_config)) {
-          resolution_type = Resolution::Step::Type::BETTER_MATCH;
-        } else if (package_is_overlay && this_config.compare(*best_config) == 0) {
-          resolution_type = Resolution::Step::Type::OVERLAID;
-        } else {
-          continue;
+          if (best_config == nullptr) {
+            resolution_type = Resolution::Step::Type::INITIAL;
+          } else if (this_config.isBetterThan(*best_config, desired_config)) {
+            resolution_type = Resolution::Step::Type::BETTER_MATCH;
+          } else if (package_is_overlay && this_config.compare(*best_config) == 0) {
+            resolution_type = Resolution::Step::Type::OVERLAID;
+          } else {
+            continue;
+          }
         }
 
         // The configuration matches and is better than the previous selection.
@@ -506,6 +509,11 @@
         best_config = &best_config_copy;
         best_offset = offset;
 
+        if (ignore_configuration) {
+          // Any configuration will suffice, so break.
+          break;
+        }
+
         if (resource_resolution_logging_enabled_) {
           resolution_steps.push_back(Resolution::Step{resolution_type,
                                                       this_config.toString(),
@@ -622,8 +630,9 @@
 
 bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const {
   FindEntryResult entry;
-  ApkAssetsCookie cookie =
-      FindEntry(resid, 0u /* density_override */, true /* stop_at_first_match */, &entry);
+  ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
+                                     true /* stop_at_first_match */,
+                                     true /* ignore_configuration */, &entry);
   if (cookie == kInvalidCookie) {
     return false;
   }
@@ -652,13 +661,14 @@
 
 bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const {
   FindEntryResult entry;
-  ApkAssetsCookie cookie =
-      FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */, &entry);
+  ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
+                                     false /* stop_at_first_match */,
+                                     true /* ignore_configuration */, &entry);
   if (cookie != kInvalidCookie) {
     *out_flags = entry.type_flags;
-    return cookie;
+    return true;
   }
-  return kInvalidCookie;
+  return false;
 }
 
 ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
@@ -666,8 +676,8 @@
                                            ResTable_config* out_selected_config,
                                            uint32_t* out_flags) const {
   FindEntryResult entry;
-  ApkAssetsCookie cookie =
-      FindEntry(resid, density_override, false /* stop_at_first_match */, &entry);
+  ApkAssetsCookie cookie = FindEntry(resid, density_override, false /* stop_at_first_match */,
+                                     false /* ignore_configuration */, &entry);
   if (cookie == kInvalidCookie) {
     return kInvalidCookie;
   }
@@ -759,8 +769,10 @@
   }
 
   FindEntryResult entry;
-  ApkAssetsCookie cookie =
-      FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */, &entry);
+  ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
+                                     false /* stop_at_first_match */,
+                                     false /* ignore_configuration */,
+                                     &entry);
   if (cookie == kInvalidCookie) {
     return nullptr;
   }
@@ -1387,7 +1399,9 @@
             // Find the cookie of the attribute resource id
             FindEntryResult attribute_entry_result;
             ApkAssetsCookie attribute_cookie =
-                o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ , false,
+                o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ ,
+                                            true /* stop_at_first_match */,
+                                            true /* ignore_configuration */,
                                             &attribute_entry_result);
 
             // Determine the package id of the attribute in the destination AssetManager
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index fc5aa9c7..1e2b36c 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -257,11 +257,12 @@
   // Creates a new Theme from this AssetManager.
   std::unique_ptr<Theme> NewTheme();
 
-  template <typename Func>
-  void ForEachPackage(Func func) const {
+  void ForEachPackage(const std::function<bool(const std::string&, uint8_t)> func) const {
     for (const PackageGroup& package_group : package_groups_) {
-      func(package_group.packages_.front().loaded_package_->GetPackageName(),
-           package_group.dynamic_ref_table.mAssignedPackageId);
+      if (!func(package_group.packages_.front().loaded_package_->GetPackageName(),
+           package_group.dynamic_ref_table.mAssignedPackageId)) {
+        return;
+      }
     }
   }
 
@@ -282,10 +283,13 @@
   // care about the value. In this case, the value of `FindEntryResult::type_flags` is incomplete
   // and should not be used.
   //
+  // When `ignore_configuration` is true, FindEntry will return always select the first entry in
+  // for the type seen regardless of its configuration.
+  //
   // NOTE: FindEntry takes care of ensuring that structs within FindEntryResult have been properly
   // bounds-checked. Callers of FindEntry are free to trust the data if this method succeeds.
   ApkAssetsCookie FindEntry(uint32_t resid, uint16_t density_override, bool stop_at_first_match,
-                            FindEntryResult* out_entry) const;
+                            bool ignore_configuration, FindEntryResult* out_entry) const;
 
   // Assigns package IDs to all shared library ApkAssets.
   // Should be called whenever the ApkAssets are changed.
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 0032960..ffc1a92 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -44,6 +44,7 @@
 
 Maybe<ResourceName> ToResourceName(
     const android::ResTable::resource_name& name_in) {
+  // TODO: Remove this when ResTable and AssetManager(1) are removed from AAPT2
   ResourceName name_out;
   if (!name_in.package) {
     return {};
@@ -79,6 +80,41 @@
   return name_out;
 }
 
+Maybe<ResourceName> ToResourceName(const android::AssetManager2::ResourceName& name_in) {
+  ResourceName name_out;
+  if (!name_in.package) {
+    return {};
+  }
+
+  name_out.package = std::string(name_in.package, name_in.package_len);
+
+  const ResourceType* type;
+  if (name_in.type16) {
+    type = ParseResourceType(
+        util::Utf16ToUtf8(StringPiece16(name_in.type16, name_in.type_len)));
+  } else if (name_in.type) {
+    type = ParseResourceType(StringPiece(name_in.type, name_in.type_len));
+  } else {
+    return {};
+  }
+
+  if (!type) {
+    return {};
+  }
+
+  name_out.type = *type;
+
+  if (name_in.entry16) {
+    name_out.entry =
+        util::Utf16ToUtf8(StringPiece16(name_in.entry16, name_in.entry_len));
+  } else if (name_in.entry) {
+    name_out.entry = std::string(name_in.entry, name_in.entry_len);
+  } else {
+    return {};
+  }
+  return name_out;
+}
+
 bool ParseResourceName(const StringPiece& str, ResourceNameRef* out_ref,
                        bool* out_private) {
   if (str.empty()) {
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index e282fd58..a8a3120 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -20,6 +20,7 @@
 #include <functional>
 #include <memory>
 
+#include "androidfw/AssetManager2.h"
 #include "androidfw/ConfigDescription.h"
 #include "androidfw/ResourceTypes.h"
 #include "androidfw/StringPiece.h"
@@ -78,6 +79,12 @@
     const android::ResTable::resource_name& name);
 
 /**
+ * Convert an android::AssetManager2::ResourceName to an aapt::ResourceName struct.
+ */
+Maybe<ResourceName> ToResourceName(
+    const android::AssetManager2::ResourceName& name_in);
+
+/**
  * Returns a boolean value if the string is equal to TRUE, true, True, FALSE,
  * false, or False.
  */
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 22edd2f..a7b8d25 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -717,28 +717,20 @@
   return true;
 }
 
-static int32_t FindFrameworkAssetManagerCookie(const android::AssetManager& assets) {
+static android::ApkAssetsCookie FindFrameworkAssetManagerCookie(
+    const android::AssetManager2& assets) {
   using namespace android;
 
   // Find the system package (0x01). AAPT always generates attributes with the type 0x01, so
   // we're looking for the first attribute resource in the system package.
-  const ResTable& table = assets.getResources(true);
-  Res_value val;
-  ssize_t idx = table.getResource(0x01010000, &val, true);
-  if (idx != NO_ERROR) {
-    // Try as a bag.
-    const ResTable::bag_entry* entry;
-    ssize_t cnt = table.lockBag(0x01010000, &entry);
-    if (cnt >= 0) {
-      idx = entry->stringBlock;
-    }
-    table.unlockBag(entry);
-  }
+  Res_value val{};
+  ResTable_config config{};
+  uint32_t type_spec_flags;
+  ApkAssetsCookie idx = assets.GetResource(0x01010000, true /** may_be_bag */,
+                                           0 /** density_override */, &val, &config,
+                                           &type_spec_flags);
 
-  if (idx < 0) {
-    return 0;
-  }
-  return table.getTableCookie(idx);
+  return idx;
 }
 
 class Linker {
@@ -750,17 +742,17 @@
         file_collection_(util::make_unique<io::FileCollection>()) {
   }
 
-  void ExtractCompileSdkVersions(android::AssetManager* assets) {
+  void ExtractCompileSdkVersions(android::AssetManager2* assets) {
     using namespace android;
 
-    int32_t cookie = FindFrameworkAssetManagerCookie(*assets);
-    if (cookie == 0) {
+    android::ApkAssetsCookie cookie = FindFrameworkAssetManagerCookie(*assets);
+    if (cookie == android::kInvalidCookie) {
       // No Framework assets loaded. Not a failure.
       return;
     }
 
     std::unique_ptr<Asset> manifest(
-        assets->openNonAsset(cookie, kAndroidManifestPath, Asset::AccessMode::ACCESS_BUFFER));
+        assets->OpenNonAsset(kAndroidManifestPath, cookie, Asset::AccessMode::ACCESS_BUFFER));
     if (manifest == nullptr) {
       // No errors.
       return;
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index a844a43..78e0074 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -20,9 +20,11 @@
 
 #include "android-base/logging.h"
 #include "android-base/stringprintf.h"
-#include "androidfw/AssetManager.h"
+#include "androidfw/Asset.h"
+#include "androidfw/AssetManager2.h"
 #include "androidfw/ConfigDescription.h"
 #include "androidfw/ResourceTypes.h"
+#include "androidfw/ResourceUtils.h"
 
 #include "NameMangler.h"
 #include "Resource.h"
@@ -30,6 +32,7 @@
 #include "ValueVisitor.h"
 #include "util/Util.h"
 
+using ::android::ApkAssets;
 using ::android::ConfigDescription;
 using ::android::StringPiece;
 using ::android::StringPiece16;
@@ -214,51 +217,75 @@
 }
 
 bool AssetManagerSymbolSource::AddAssetPath(const StringPiece& path) {
-  int32_t cookie = 0;
-  return assets_.addAssetPath(android::String8(path.data(), path.size()), &cookie);
+  if (std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path.data())) {
+    apk_assets_.push_back(std::move(apk));
+
+    std::vector<const ApkAssets*> apk_assets;
+    for (const std::unique_ptr<const ApkAssets>& apk_asset : apk_assets_) {
+      apk_assets.push_back(apk_asset.get());
+    }
+
+    asset_manager_.SetApkAssets(apk_assets, true /* invalidate_caches */,
+                                false /* filter_incompatible_configs */);
+    return true;
+  }
+  return false;
 }
 
 std::map<size_t, std::string> AssetManagerSymbolSource::GetAssignedPackageIds() const {
   std::map<size_t, std::string> package_map;
-  const android::ResTable& table = assets_.getResources(false);
-  const size_t package_count = table.getBasePackageCount();
-  for (size_t i = 0; i < package_count; i++) {
-    package_map[table.getBasePackageId(i)] =
-        util::Utf16ToUtf8(android::StringPiece16(table.getBasePackageName(i).string()));
-  }
+  asset_manager_.ForEachPackage([&package_map](const std::string& name, uint8_t id) -> bool {
+    package_map.insert(std::make_pair(id, name));
+    return true;
+  });
+
   return package_map;
 }
 
 bool AssetManagerSymbolSource::IsPackageDynamic(uint32_t packageId) const {
-  return assets_.getResources(false).isPackageDynamic(packageId);
+  if (packageId == 0) {
+    return true;
+  }
+
+  for (const std::unique_ptr<const ApkAssets>& assets : apk_assets_) {
+    for (const std::unique_ptr<const android::LoadedPackage>& loaded_package
+         : assets->GetLoadedArsc()->GetPackages()) {
+      if (packageId == loaded_package->GetPackageId() && loaded_package->IsDynamic()) {
+        return true;
+      }
+    }
+  }
+
+  return false;
 }
 
 static std::unique_ptr<SymbolTable::Symbol> LookupAttributeInTable(
-    const android::ResTable& table, ResourceId id) {
-  // Try as a bag.
-  const android::ResTable::bag_entry* entry;
-  ssize_t count = table.lockBag(id.id, &entry);
-  if (count < 0) {
-    table.unlockBag(entry);
+    android::AssetManager2& am, ResourceId id) {
+  if (am.GetApkAssets().empty()) {
+    return {};
+  }
+
+  const android::ResolvedBag* bag = am.GetBag(id.id);
+  if (bag == nullptr) {
     return nullptr;
   }
 
   // We found a resource.
   std::unique_ptr<SymbolTable::Symbol> s = util::make_unique<SymbolTable::Symbol>(id);
 
-  // Check to see if it is an attribute.
-  for (size_t i = 0; i < (size_t)count; i++) {
-    if (entry[i].map.name.ident == android::ResTable_map::ATTR_TYPE) {
-      s->attribute = std::make_shared<Attribute>(entry[i].map.value.data);
+  const size_t count = bag->entry_count;
+  for (uint32_t i = 0; i < count; i++) {
+    if (bag->entries[i].key == android::ResTable_map::ATTR_TYPE) {
+      s->attribute = std::make_shared<Attribute>(bag->entries[i].value.data);
       break;
     }
   }
 
   if (s->attribute) {
-    for (size_t i = 0; i < (size_t)count; i++) {
-      const android::ResTable_map& map_entry = entry[i].map;
-      if (Res_INTERNALID(map_entry.name.ident)) {
-        switch (map_entry.name.ident) {
+    for (size_t i = 0; i < count; i++) {
+      const android::ResolvedBag::Entry& map_entry = bag->entries[i];
+      if (Res_INTERNALID(map_entry.key)) {
+        switch (map_entry.key) {
           case android::ResTable_map::ATTR_MIN:
             s->attribute->min_int = static_cast<int32_t>(map_entry.value.data);
             break;
@@ -269,74 +296,65 @@
         continue;
       }
 
-      android::ResTable::resource_name entry_name;
-      if (!table.getResourceName(map_entry.name.ident, false, &entry_name)) {
-        table.unlockBag(entry);
+      android::AssetManager2::ResourceName name;
+      if (!am.GetResourceName(map_entry.key, &name)) {
         return nullptr;
       }
 
-      Maybe<ResourceName> parsed_name = ResourceUtils::ToResourceName(entry_name);
+      Maybe<ResourceName> parsed_name = ResourceUtils::ToResourceName(name);
       if (!parsed_name) {
         return nullptr;
       }
 
       Attribute::Symbol symbol;
       symbol.symbol.name = parsed_name.value();
-      symbol.symbol.id = ResourceId(map_entry.name.ident);
+      symbol.symbol.id = ResourceId(map_entry.key);
       symbol.value = map_entry.value.data;
       s->attribute->symbols.push_back(std::move(symbol));
     }
   }
-  table.unlockBag(entry);
+
   return s;
 }
 
 std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindByName(
     const ResourceName& name) {
-  const android::ResTable& table = assets_.getResources(false);
+  const std::string mangled_entry = NameMangler::MangleEntry(name.package, name.entry);
 
-  const std::u16string package16 = util::Utf8ToUtf16(name.package);
-  const std::u16string type16 = util::Utf8ToUtf16(to_string(name.type));
-  const std::u16string entry16 = util::Utf8ToUtf16(name.entry);
-  const std::u16string mangled_entry16 =
-      util::Utf8ToUtf16(NameMangler::MangleEntry(name.package, name.entry));
-
+  bool found = false;
+  ResourceId res_id = 0;
   uint32_t type_spec_flags;
-  ResourceId res_id;
 
   // There can be mangled resources embedded within other packages. Here we will
   // look into each package and look-up the mangled name until we find the resource.
-  const size_t count = table.getBasePackageCount();
-  for (size_t i = 0; i < count; i++) {
-    const android::String16 package_name = table.getBasePackageName(i);
-    StringPiece16 real_package16 = package16;
-    StringPiece16 real_entry16 = entry16;
-    std::u16string scratch_entry16;
-    if (StringPiece16(package_name) != package16) {
-      real_entry16 = mangled_entry16;
-      real_package16 = package_name.string();
+  asset_manager_.ForEachPackage([&](const std::string& package_name, uint8_t id) -> bool {
+    ResourceName real_name(name.package, name.type, name.entry);
+
+    if (package_name != name.package) {
+      real_name.entry = mangled_entry;
+      real_name.package = package_name;
     }
 
-    type_spec_flags = 0;
-    res_id = table.identifierForName(real_entry16.data(), real_entry16.size(), type16.data(),
-                                     type16.size(), real_package16.data(), real_package16.size(),
-                                     &type_spec_flags);
-    if (res_id.is_valid()) {
-      break;
+    res_id = asset_manager_.GetResourceId(real_name.to_string());
+    if (res_id.is_valid() && asset_manager_.GetResourceFlags(res_id.id, &type_spec_flags)) {
+      found = true;
+      return false;
     }
-  }
 
-  if (!res_id.is_valid()) {
+    return true;
+  });
+
+  if (!found) {
     return {};
   }
 
   std::unique_ptr<SymbolTable::Symbol> s;
   if (name.type == ResourceType::kAttr) {
-    s = LookupAttributeInTable(table, res_id);
+    s = LookupAttributeInTable(asset_manager_, res_id);
   } else {
     s = util::make_unique<SymbolTable::Symbol>();
     s->id = res_id;
-    s->is_dynamic = table.isResourceDynamic(res_id.id);
+    s->is_dynamic = IsPackageDynamic(ResourceId(res_id).package_id());
   }
 
   if (s) {
@@ -346,13 +364,13 @@
   return {};
 }
 
-static Maybe<ResourceName> GetResourceName(const android::ResTable& table,
+static Maybe<ResourceName> GetResourceName(android::AssetManager2& am,
                                            ResourceId id) {
-  android::ResTable::resource_name res_name = {};
-  if (!table.getResourceName(id.id, true, &res_name)) {
+  android::AssetManager2::ResourceName name;
+  if (!am.GetResourceName(id.id, &name)) {
     return {};
   }
-  return ResourceUtils::ToResourceName(res_name);
+  return ResourceUtils::ToResourceName(name);
 }
 
 std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindById(
@@ -361,22 +379,30 @@
     // Exit early and avoid the error logs from AssetManager.
     return {};
   }
-  const android::ResTable& table = assets_.getResources(false);
-  Maybe<ResourceName> maybe_name = GetResourceName(table, id);
+
+  if (apk_assets_.empty()) {
+    return {};
+  }
+
+  Maybe<ResourceName> maybe_name = GetResourceName(asset_manager_, id);
   if (!maybe_name) {
     return {};
   }
 
-  uint32_t type_spec_flags = 0;
-  table.getResourceFlags(id.id, &type_spec_flags);
 
+  uint32_t type_spec_flags = 0;
+  if (!asset_manager_.GetResourceFlags(id.id, &type_spec_flags)) {
+    return {};
+  }
+
+  ResourceName& name = maybe_name.value();
   std::unique_ptr<SymbolTable::Symbol> s;
-  if (maybe_name.value().type == ResourceType::kAttr) {
-    s = LookupAttributeInTable(table, id);
+  if (name.type == ResourceType::kAttr) {
+    s = LookupAttributeInTable(asset_manager_, id);
   } else {
     s = util::make_unique<SymbolTable::Symbol>();
     s->id = id;
-    s->is_dynamic = table.isResourceDynamic(id.id);
+    s->is_dynamic = IsPackageDynamic(ResourceId(id).package_id());
   }
 
   if (s) {
diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h
index 2d8bd02..6997cd6 100644
--- a/tools/aapt2/process/SymbolTable.h
+++ b/tools/aapt2/process/SymbolTable.h
@@ -22,7 +22,8 @@
 #include <vector>
 
 #include "android-base/macros.h"
-#include "androidfw/AssetManager.h"
+#include "androidfw/Asset.h"
+#include "androidfw/AssetManager2.h"
 #include "utils/JenkinsHash.h"
 #include "utils/LruCache.h"
 
@@ -201,12 +202,13 @@
   std::unique_ptr<SymbolTable::Symbol> FindByReference(
       const Reference& ref) override;
 
-  android::AssetManager* GetAssetManager() {
-    return &assets_;
+  android::AssetManager2* GetAssetManager() {
+    return &asset_manager_;
   }
 
  private:
-  android::AssetManager assets_;
+  android::AssetManager2 asset_manager_;
+  std::vector<std::unique_ptr<const android::ApkAssets>> apk_assets_;
 
   DISALLOW_COPY_AND_ASSIGN(AssetManagerSymbolSource);
 };
diff --git a/tools/aapt2/process/SymbolTable_test.cpp b/tools/aapt2/process/SymbolTable_test.cpp
index 1f59d70..ddc2101 100644
--- a/tools/aapt2/process/SymbolTable_test.cpp
+++ b/tools/aapt2/process/SymbolTable_test.cpp
@@ -76,40 +76,54 @@
   EXPECT_THAT(symbol_table.FindByName(test::ParseNameOrDie("com.android.lib:id/foo")), NotNull());
 }
 
-TEST(SymbolTableTest, FindByNameWhenSymbolIsMangledInResTable) {
+using SymbolTableTestFixture = CommandTestFixture;
+TEST_F(SymbolTableTestFixture, FindByNameWhenSymbolIsMangledInResTable) {
   using namespace android;
+  StdErrDiagnostics diag;
 
-  std::unique_ptr<IAaptContext> context =
-      test::ContextBuilder()
-          .SetCompilationPackage("com.android.app")
-          .SetPackageId(0x7f)
-          .SetPackageType(PackageType::kApp)
-          .SetMinSdkVersion(SDK_LOLLIPOP_MR1)
-          .SetNameManglerPolicy(NameManglerPolicy{"com.android.app"})
-          .Build();
+  // Create a static library.
+  const std::string static_lib_compiled_files_dir = GetTestPath("static-lib-compiled");
+  ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"),
+         R"(<?xml version="1.0" encoding="utf-8"?>
+         <resources>
+             <item type="id" name="foo"/>
+        </resources>)",
+         static_lib_compiled_files_dir, &diag));
 
-  // Create a ResourceTable with a mangled resource, simulating a static library being merged into
-  // the main application package.
-  std::unique_ptr<ResourceTable> table =
-      test::ResourceTableBuilder()
-          .AddSimple("com.android.app:id/" + NameMangler::MangleEntry("com.android.lib", "foo"),
-                     ResourceId(0x7f020000))
-          .AddSimple("com.android.app:id/bar", ResourceId(0x7f020001))
-          .Build();
+  const std::string static_lib_apk = GetTestPath("static_lib.apk");
+  std::vector<std::string> link_args = {
+      "--manifest", GetDefaultManifest("com.android.lib"),
+      "--min-sdk-version", "22",
+      "--static-lib",
+      "-o", static_lib_apk,
+  };
+  ASSERT_TRUE(Link(link_args, static_lib_compiled_files_dir, &diag));
 
-  BigBuffer buffer(1024u);
-  TableFlattener flattener({}, &buffer);
-  ASSERT_TRUE(flattener.Consume(context.get(), table.get()));
+  // Merge the static library into the main application package. The static library resources will
+  // be mangled with the library package name.
+  const std::string app_compiled_files_dir = GetTestPath("app-compiled");
+  ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"),
+      R"(<?xml version="1.0" encoding="utf-8"?>
+         <resources>
+             <item type="id" name="bar"/>
+        </resources>)",
+        app_compiled_files_dir, &diag));
 
-  std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
+  const std::string out_apk = GetTestPath("out.apk");
+  link_args = {
+      "--manifest", GetDefaultManifest("com.android.app"),
+      "--min-sdk-version", "22",
+      "-o", out_apk,
+      static_lib_apk
+  };
+  ASSERT_TRUE(Link(link_args, app_compiled_files_dir, &diag));
 
   // Construct the test AssetManager.
   auto asset_manager_source = util::make_unique<AssetManagerSymbolSource>();
-  ResTable& res_table = const_cast<ResTable&>(
-      asset_manager_source->GetAssetManager()->getResources(false /*required*/));
-  ASSERT_THAT(res_table.add(data.get(), buffer.size()), Eq(NO_ERROR));
+  asset_manager_source->AddAssetPath(out_apk);
 
-  SymbolTable symbol_table(context->GetNameMangler());
+  NameMangler name_mangler(NameManglerPolicy{"com.android.app"});
+  SymbolTable symbol_table(&name_mangler);
   symbol_table.AppendSource(std::move(asset_manager_source));
 
   EXPECT_THAT(symbol_table.FindByName(test::ParseNameOrDie("com.android.lib:id/foo")), NotNull());
diff --git a/tools/aapt2/test/Fixture.cpp b/tools/aapt2/test/Fixture.cpp
index 3fcdfb7..a51b4a4 100644
--- a/tools/aapt2/test/Fixture.cpp
+++ b/tools/aapt2/test/Fixture.cpp
@@ -37,6 +37,8 @@
 
 namespace aapt {
 
+const char* CommandTestFixture::kDefaultPackageName = "com.aapt.command.test";
+
 void ClearDirectory(const android::StringPiece& path) {
   const std::string root_dir = path.to_string();
   std::unique_ptr<DIR, decltype(closedir)*> dir(opendir(root_dir.data()), closedir);
@@ -124,12 +126,12 @@
   return LinkCommand(diag).Execute(link_args, &std::cerr) == 0;
 }
 
-std::string CommandTestFixture::GetDefaultManifest() {
+std::string CommandTestFixture::GetDefaultManifest(const char* package_name) {
   const std::string manifest_file = GetTestPath("AndroidManifest.xml");
-  CHECK(WriteFile(manifest_file, R"(
+  CHECK(WriteFile(manifest_file, android::base::StringPrintf(R"(
       <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.aapt.command.test">
-      </manifest>)"));
+          package="%s">
+      </manifest>)", package_name)));
   return manifest_file;
 }
 
diff --git a/tools/aapt2/test/Fixture.h b/tools/aapt2/test/Fixture.h
index 3079c75..fce2aeb 100644
--- a/tools/aapt2/test/Fixture.h
+++ b/tools/aapt2/test/Fixture.h
@@ -81,7 +81,7 @@
             IDiagnostics* diag);
 
   // Creates a minimal android manifest within the test directory and returns the file path.
-  std::string GetDefaultManifest();
+  std::string GetDefaultManifest(const char* package_name = kDefaultPackageName);
 
   // Returns pointer to data inside APK files
   std::unique_ptr<io::IData> OpenFileAsData(LoadedApk* apk,
@@ -91,6 +91,7 @@
   void AssertLoadXml(LoadedApk* apk, const io::IData* data,
                      android::ResXMLTree* out_tree);
 
+  static const char* kDefaultPackageName;
  private:
   DISALLOW_COPY_AND_ASSIGN(CommandTestFixture);
 };
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 604b257..5d57de6 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -102,12 +102,21 @@
 #endif
 
 bool mkdirs(const std::string& path) {
-  #ifdef _WIN32
-  // Start after the drive path if present. Calling mkdir with only the drive will cause an error.
-  size_t current_pos = 1u;
-  if (path.size() >= 3 && path[1] == ':' &&
-        (path[2] == '\\' || path[2] == '/')) {
-    current_pos = 3u;
+ #ifdef _WIN32
+  // Start after the long path prefix if present.
+  bool require_drive = false;
+  size_t current_pos = 0u;
+  if (util::StartsWith(path, R"(\\?\)")) {
+    require_drive = true;
+    current_pos = 4u;
+  }
+
+  // Start after the drive path if present.
+  if (path.size() >= 3 && path[current_pos + 1] == ':' &&
+       (path[current_pos + 2] == '\\' || path[current_pos + 2] == '/')) {
+    current_pos += 3u;
+  } else if (require_drive) {
+    return false;
   }
  #else
   // Start after the first character so that we don't consume the root '/'.
diff --git a/tools/aapt2/util/Files_test.cpp b/tools/aapt2/util/Files_test.cpp
index 202cc26..6c38080 100644
--- a/tools/aapt2/util/Files_test.cpp
+++ b/tools/aapt2/util/Files_test.cpp
@@ -19,6 +19,7 @@
 #include <sstream>
 
 #include "android-base/stringprintf.h"
+#include "android-base/utf8.h"
 
 #include "test/Test.h"
 
@@ -65,5 +66,40 @@
   EXPECT_EQ(expected_path_, base);
 }
 
+#ifdef _WIN32
+TEST_F(FilesTest, WindowsMkdirsLongPath) {
+  // Creating directory paths longer than the Windows maximum path length (260 charatcers) should
+  // succeed.
+  const std::string kDirName = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+  const size_t kRecursiveDepth = 10u;
+
+  // Recursively create the test file path and clean up the created directories after the files have
+  // been created.
+  std::function<void(std::string, size_t)> CreateResursiveDirs =
+      [&kDirName, &CreateResursiveDirs](std::string current_path, const size_t n) -> void {
+    AppendPath(&current_path, kDirName);
+
+    if (n == 0) {
+      ASSERT_TRUE(file::mkdirs(current_path)) << "Failed to create path " << current_path;
+    } else {
+      CreateResursiveDirs(current_path, n - 1);
+    }
+
+    // Clean up the created directories.
+    _rmdir(current_path.data());
+  };
+
+  CreateResursiveDirs(
+      android::base::StringPrintf(R"(\\?\%s)", android::base::GetExecutableDirectory().data()),
+      kRecursiveDepth);
+}
+
+TEST_F(FilesTest, WindowsMkdirsLongPathMissingDrive) {
+  ASSERT_FALSE(file::mkdirs(R"(\\?\local\path\to\file)"));
+  ASSERT_FALSE(file::mkdirs(R"(\\?\:local\path\to\file)"));
+  ASSERT_FALSE(file::mkdirs(R"(\\?\\local\path\to\file)"));
+}
+#endif
+
 }  // namespace files
 }  // namespace aapt