Manually calculate stats for app owning external storage

The stats are calculated using quota APIs for all the apps.
This is going wrong for the app owning external storage, as it includes
the external storage files also. The reason for that is the uid for the
external storage files and the app owning the external storage is the
same. Calculating the size manually avoids the problem.

Bug: http://b/195804288
Test: atest StorageHostTest
Test: atest installd_service_test.cpp
Change-Id: I183c6997375b94dc02562bede03e3a15036efb6e
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index acba0b9..027c486 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1940,7 +1940,18 @@
     }
     fts_close(fts);
 }
-
+static bool ownsExternalStorage(int32_t appId) {
+    //  Fetch external storage owner appid  and check if it is the same as the
+    //  current appId whose size is calculated
+    struct stat s;
+    auto _picDir = StringPrintf("%s/Pictures", create_data_media_path(nullptr, 0).c_str());
+    // check if the stat are present
+    if (stat(_picDir.c_str(), &s) == 0) {
+        // fetch the appId from the uid of the media app
+        return ((int32_t)multiuser_get_app_id(s.st_uid) == appId);
+    }
+    return false;
+}
 binder::Status InstalldNativeService::getAppSize(const std::optional<std::string>& uuid,
         const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
         int32_t appId, const std::vector<int64_t>& ceDataInodes,
@@ -1995,8 +2006,10 @@
         calculate_tree_size(obbCodePath, &extStats.codeSize);
     }
     ATRACE_END();
-
-    if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START) {
+    // Calculating the app size of the external storage owning app in a manual way, since
+    // calculating it through quota apis also includes external media storage in the app storage
+    // numbers
+    if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START && !ownsExternalStorage(appId)) {
         ATRACE_BEGIN("code");
         for (const auto& codePath : codePaths) {
             calculate_tree_size(codePath, &stats.codeSize, -1,
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 13e15ca..4cde7e3 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -13,7 +13,10 @@
     test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_utils_test.cpp"],
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     shared_libs: [
         "libbase",
         "libutils",
@@ -33,7 +36,10 @@
     test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_cache_test.cpp"],
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     shared_libs: [
         "libbase",
         "libbinder",
@@ -75,7 +81,10 @@
     test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_service_test.cpp"],
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     shared_libs: [
         "libbase",
         "libbinder",
@@ -84,6 +93,7 @@
         "libprocessgroup",
         "libselinux",
         "libutils",
+        "packagemanager_aidl-cpp",
         "server_configurable_flags",
     ],
     static_libs: [
@@ -117,7 +127,10 @@
     test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_dexopt_test.cpp"],
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     shared_libs: [
         "libbase",
         "libbinder",
@@ -160,7 +173,10 @@
     test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_otapreopt_test.cpp"],
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     shared_libs: [
         "libbase",
         "libcutils",
@@ -169,6 +185,6 @@
     ],
     static_libs: [
         "liblog",
-        "libotapreoptparameters"
+        "libotapreoptparameters",
     ],
 }
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 1e7559d..3657497 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -18,10 +18,11 @@
 #include <string>
 
 #include <fcntl.h>
+#include <pwd.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/statvfs.h>
 #include <sys/stat.h>
+#include <sys/statvfs.h>
 #include <sys/xattr.h>
 
 #include <android-base/file.h>
@@ -32,8 +33,10 @@
 #include <cutils/properties.h>
 #include <gtest/gtest.h>
 
-#include "binder_test_utils.h"
+#include <android/content/pm/IPackageManagerNative.h>
+#include <binder/IServiceManager.h>
 #include "InstalldNativeService.h"
+#include "binder_test_utils.h"
 #include "dexopt.h"
 #include "globals.h"
 #include "utils.h"
@@ -41,6 +44,34 @@
 using android::base::StringPrintf;
 
 namespace android {
+std::string get_package_name(uid_t uid) {
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<content::pm::IPackageManagerNative> package_mgr;
+    if (sm.get() == nullptr) {
+        LOG(INFO) << "Cannot find service manager";
+    } else {
+        sp<IBinder> binder = sm->getService(String16("package_native"));
+        if (binder.get() == nullptr) {
+            LOG(INFO) << "Cannot find package_native";
+        } else {
+            package_mgr = interface_cast<content::pm::IPackageManagerNative>(binder);
+        }
+    }
+    // find package name
+    std::string pkg;
+    if (package_mgr != nullptr) {
+        std::vector<std::string> names;
+        binder::Status status = package_mgr->getNamesForUids({(int)uid}, &names);
+        if (!status.isOk()) {
+            LOG(INFO) << "getNamesForUids failed: %s", status.exceptionMessage().c_str();
+        } else {
+            if (!names[0].empty()) {
+                pkg = names[0].c_str();
+            }
+        }
+    }
+    return pkg;
+}
 namespace installd {
 
 constexpr const char* kTestUuid = "TEST";
@@ -247,7 +278,50 @@
     EXPECT_TRUE(create_cache_path(buf, "/path/to/file.apk", "isa"));
     EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf));
 }
+TEST_F(ServiceTest, GetAppSize) {
+    struct stat s;
 
+    std::string externalPicDir =
+            StringPrintf("%s/Pictures", create_data_media_path(nullptr, 0).c_str());
+    if (stat(externalPicDir.c_str(), &s) == 0) {
+        // fetch the appId from the uid of the external storage owning app
+        int32_t externalStorageAppId = multiuser_get_app_id(s.st_uid);
+        // Fetch Package Name for the external storage owning app uid
+        std::string pkg = get_package_name(s.st_uid);
+
+        std::vector<int64_t> externalStorageSize, externalStorageSizeAfterAddingExternalFile;
+        std::vector<int64_t> ceDataInodes;
+
+        std::vector<std::string> codePaths;
+        std::vector<std::string> packageNames;
+        // set up parameters
+        packageNames.push_back(pkg);
+        ceDataInodes.push_back(0);
+        // initialise the mounts
+        service->invalidateMounts();
+        // call the getAppSize to get the current size of the external storage owning app
+        service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
+                            externalStorageAppId, ceDataInodes, codePaths, &externalStorageSize);
+        // add a file with 20MB size to the external storage
+        std::string externalFileLocation =
+                StringPrintf("%s/Pictures/%s", getenv("EXTERNAL_STORAGE"), "External.jpg");
+        std::string externalFileContentCommand =
+                StringPrintf("dd if=/dev/zero of=%s bs=1M count=20", externalFileLocation.c_str());
+        system(externalFileContentCommand.c_str());
+        // call the getAppSize again to get the new size of the external storage owning app
+        service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
+                            externalStorageAppId, ceDataInodes, codePaths,
+                            &externalStorageSizeAfterAddingExternalFile);
+        // check that the size before adding the file and after should be the same, as the app size
+        // is not changed.
+        for (size_t i = 0; i < externalStorageSize.size(); i++) {
+            ASSERT_TRUE(externalStorageSize[i] == externalStorageSizeAfterAddingExternalFile[i]);
+        }
+        // remove the external file
+        std::string removeCommand = StringPrintf("rm -f %s", externalFileLocation.c_str());
+        system(removeCommand.c_str());
+    }
+}
 static bool mkdirs(const std::string& path, mode_t mode) {
     struct stat sb;
     if (stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) {