Use inode numbers for CE storage, fix sizes.

Certain operations, such as clearing/destroying app data, or just
counting on-disk size, require us to know the CE storage directory
of a particular app.  To facilitate these operations, offer a method
to get the inode of a CE directory, and accept that inode number
for later operations.

In previous releases, we started installing apps using a new
directory-based layout, where all app code, unpacked native libraries,
and optimized code is bundled together.  So now we only have a single
path to measure for code size.

Start measuring both CE and DE storage data usage for apps, and tweak
the reporting so that empty cache/data directories actually show up
as "0 bytes".

Fix bugs in disk usage counting, since st_blksize has no bearing on
the allocated disk space.  Also don't double-count "." and ".."
directories when measuring storage.

Bug: 27828915, 27197819
Change-Id: I350b951f5c24165edb253ac663c9aae020c24dc9
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index d84d9f6..878fb2d 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -81,11 +81,39 @@
  * volume UUID, package name, and user ID. An empty UUID is assumed to be
  * internal storage.
  */
-std::string create_data_user_package_path(const char* volume_uuid,
+std::string create_data_user_ce_package_path(const char* volume_uuid,
         userid_t user, const char* package_name) {
     check_package_name(package_name);
     return StringPrintf("%s/%s",
-            create_data_user_path(volume_uuid, user).c_str(), package_name);
+            create_data_user_ce_path(volume_uuid, user).c_str(), package_name);
+}
+
+std::string create_data_user_ce_package_path(const char* volume_uuid, userid_t user,
+        const char* package_name, ino_t ce_data_inode) {
+    // For testing purposes, rely on the inode when defined; this could be
+    // optimized to use access() in the future.
+    auto fallback = create_data_user_ce_package_path(volume_uuid, user, package_name);
+    if (ce_data_inode != 0) {
+        auto user_path = create_data_user_ce_path(volume_uuid, user);
+        DIR* dir = opendir(user_path.c_str());
+        if (dir == nullptr) {
+            PLOG(ERROR) << "Failed to opendir " << user_path;
+            return fallback;
+        }
+
+        struct dirent* ent;
+        while ((ent = readdir(dir))) {
+            if (ent->d_ino == ce_data_inode) {
+                closedir(dir);
+                return StringPrintf("%s/%s", user_path.c_str(), ent->d_name);
+            }
+        }
+        LOG(WARNING) << "Failed to find inode " << ce_data_inode << " for package " << package_name;
+        closedir(dir);
+        return fallback;
+    } else {
+        return fallback;
+    }
 }
 
 std::string create_data_user_de_package_path(const char* volume_uuid,
@@ -102,7 +130,7 @@
         return -1;
     }
 
-    std::string _tmp(create_data_user_package_path(nullptr, userid, pkgname) + postfix);
+    std::string _tmp(create_data_user_ce_package_path(nullptr, userid, pkgname) + postfix);
     const char* tmp = _tmp.c_str();
     if (strlen(tmp) >= PKG_PATH_MAX) {
         path[0] = '\0';
@@ -132,7 +160,7 @@
 /**
  * Create the path name for user data for a certain userid.
  */
-std::string create_data_user_path(const char* volume_uuid, userid_t userid) {
+std::string create_data_user_ce_path(const char* volume_uuid, userid_t userid) {
     std::string data(create_data_path(volume_uuid));
     if (volume_uuid == nullptr) {
         if (userid == 0) {