ApexFile::GetPath() returns realpath

When an APEX file is on a symlink directory (e.g. /system_ext/apex which
actually is /system/system_ext/apex on a device where system_ext is not
a real partition), the apex info constructed by scanning the directory
can be different from apex info re-constructed by reading /proc/mounts.
The latter shows realpath, while the former isn't.

This can make getAllPackages() incorrect. It is a union of the active
apexes gathered from /proc/mounts and factory apexes gathered by
scanning the built-in directories.

Fixing the bug by storing realpath of the apex file to the ApexFile
struct.

Bug: 179211712
Test: ApexTestCases.ApexServiceTest#GetAllPackages
Test: ApexTestCasea.ApexFileTest#GetPathReturnsRealpath
Change-Id: I5da96f78ddb11609c1271edfd1044d1979180b3c
diff --git a/apexd/apex_file.cpp b/apexd/apex_file.cpp
index d65d426..9dfd3f5 100644
--- a/apexd/apex_file.cpp
+++ b/apexd/apex_file.cpp
@@ -157,8 +157,16 @@
     return manifest.error();
   }
 
-  return ApexFile(path, image_offset, image_size, std::move(*manifest), pubkey,
-                  fs_type, is_compressed);
+  // b/179211712 the stored path should be the realpath, otherwise the path we
+  // get by scanning the directory would be different from the path we get
+  // by reading /proc/mounts, if the apex file is on a symlink dir.
+  std::string realpath;
+  if (!android::base::Realpath(path, &realpath)) {
+    return ErrnoError() << "can't get realpath of " << path;
+  }
+
+  return ApexFile(realpath, image_offset, image_size, std::move(*manifest),
+                  pubkey, fs_type, is_compressed);
 }
 
 // AVB-related code.
diff --git a/apexd/apex_file_test.cpp b/apexd/apex_file_test.cpp
index 39d664d..2023646 100644
--- a/apexd/apex_file_test.cpp
+++ b/apexd/apex_file_test.cpp
@@ -293,6 +293,25 @@
   ASSERT_FALSE(*exist);
 }
 
+TEST(ApexFileTest, GetPathReturnsRealpath) {
+  const std::string real_path = kTestDataDir + "apex.apexd_test.apex";
+  const std::string symlink_path =
+      kTestDataDir + "apex.apexd_test.symlink.apex";
+
+  // In case the link already exists
+  int ret = unlink(symlink_path.c_str());
+  ASSERT_TRUE(ret == 0 || errno == ENOENT)
+      << "failed to unlink " << symlink_path;
+
+  ret = symlink(real_path.c_str(), symlink_path.c_str());
+  ASSERT_EQ(0, ret) << "failed to create symlink at " << symlink_path;
+
+  // Open with the symlink. Realpath is expected.
+  Result<ApexFile> apex_file = ApexFile::Open(symlink_path);
+  ASSERT_RESULT_OK(apex_file);
+  ASSERT_EQ(real_path, apex_file->GetPath());
+}
+
 }  // namespace
 }  // namespace apex
 }  // namespace android