AFW: Lookup shared library resource ids

Shared libraries were failing to retrieve correct resource ids from the
values of attributes in xml files. The packages of the shared ids were
not changed from 0 to their runtime assigned package ids.

Bug: 112776204
Test: atest FieldsClassificationTest#testGetAlgorithm
Change-Id: I509bc7632f5ec3e9b644e590934e6cf569a4d938
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index e39926b..bba36bc 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -136,6 +136,7 @@
         "tests/ByteBucketArray_test.cpp",
         "tests/Config_test.cpp",
         "tests/ConfigLocale_test.cpp",
+        "tests/DynamicRefTable_test.cpp",
         "tests/Idmap_test.cpp",
         "tests/LoadedArsc_test.cpp",
         "tests/ResourceUtils_test.cpp",
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 861dc0f..402e390 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -6960,6 +6960,11 @@
     uint32_t res = *resId;
     size_t packageId = Res_GETPACKAGE(res) + 1;
 
+    if (!Res_VALIDID(res)) {
+        // Cannot look up a null or invalid id, so no lookup needs to be done.
+        return NO_ERROR;
+    }
+
     if (packageId == APP_PACKAGE_ID && !mAppAsLib) {
         // No lookup needs to be done, app package IDs are absolute.
         return NO_ERROR;
@@ -6993,25 +6998,17 @@
 }
 
 status_t DynamicRefTable::lookupResourceValue(Res_value* value) const {
-    uint8_t resolvedType = Res_value::TYPE_REFERENCE;
-    switch (value->dataType) {
-    case Res_value::TYPE_ATTRIBUTE:
-        resolvedType = Res_value::TYPE_ATTRIBUTE;
-        // fallthrough
-    case Res_value::TYPE_REFERENCE:
-        if (!mAppAsLib) {
-            return NO_ERROR;
-        }
+    uint8_t resolvedType;
 
-        // If the package is loaded as shared library, the resource reference
-        // also need to be fixed.
-        break;
-    case Res_value::TYPE_DYNAMIC_ATTRIBUTE:
+    if (value->dataType == Res_value::TYPE_ATTRIBUTE
+        || value->dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE) {
         resolvedType = Res_value::TYPE_ATTRIBUTE;
-        // fallthrough
-    case Res_value::TYPE_DYNAMIC_REFERENCE:
-        break;
-    default:
+
+    } else if (value->dataType == Res_value::TYPE_REFERENCE
+               || value->dataType == Res_value::TYPE_DYNAMIC_REFERENCE) {
+        resolvedType = Res_value::TYPE_REFERENCE;
+
+    } else {
         return NO_ERROR;
     }
 
diff --git a/libs/androidfw/tests/DynamicRefTable_test.cpp b/libs/androidfw/tests/DynamicRefTable_test.cpp
new file mode 100644
index 0000000..df44e34
--- /dev/null
+++ b/libs/androidfw/tests/DynamicRefTable_test.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include "androidfw/ResourceTypes.h"
+#include "utils/String8.h"
+
+#include "gtest/gtest.h"
+namespace android {
+
+TEST(DynamicRefTableTest, LookupSharedLibSelfReferences) {
+  // Shared library
+  DynamicRefTable shared_table(0x02, /* appAsLib */ false);
+  shared_table.addMapping(0x00, 0x02);
+  Res_value value;
+  value.dataType = Res_value::TYPE_REFERENCE;
+  value.data = 0x00010000;
+  ASSERT_EQ(shared_table.lookupResourceValue(&value), NO_ERROR);
+  EXPECT_EQ(value.data, 0x02010000);
+
+  // App loaded as a shared library
+  DynamicRefTable shared_app_table(0x02, /* appAsLib */ true);
+  shared_app_table.addMapping(0x7f, 0x02);
+  Res_value value2;
+  value2.dataType = Res_value::TYPE_REFERENCE;
+  value2.data = 0x7f010000;
+  ASSERT_EQ(shared_app_table.lookupResourceValue(&value2), NO_ERROR);
+  EXPECT_EQ(value2.data, 0x02010000);
+};
+
+TEST(DynamicRefTableTest, LookupDynamicReferences) {
+  // Shared library
+  DynamicRefTable shared_table(0x2, /* appAsLib */ false);
+  shared_table.addMapping(0x00, 0x02);
+  shared_table.addMapping(0x03, 0x05);
+  Res_value value;
+  value.dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
+  value.data = 0x03010000;
+  ASSERT_EQ(shared_table.lookupResourceValue(&value), NO_ERROR);
+  EXPECT_EQ(value.data, 0x05010000);
+
+  // App loaded as a shared library
+  DynamicRefTable shared_app_table(0x2, /* appAsLib */ true);
+  shared_app_table.addMapping(0x03, 0x05);
+  shared_app_table.addMapping(0x7f, 0x2);
+  Res_value value2;
+  value2.dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
+  value2.data = 0x03010000;
+  ASSERT_EQ(shared_app_table.lookupResourceValue(&value2), NO_ERROR);
+  EXPECT_EQ(value2.data, 0x05010000);
+
+  // Regular application
+  DynamicRefTable app_table(0x7f, /* appAsLib */ false);
+  app_table.addMapping(0x03, 0x05);
+  Res_value value3;
+  value3.dataType = Res_value::TYPE_REFERENCE;
+  value3.data = 0x03010000;
+  ASSERT_EQ(app_table.lookupResourceValue(&value3), NO_ERROR);
+  EXPECT_EQ(value3.data, 0x05010000);
+};
+
+} // namespace android
\ No newline at end of file