Define range of GIDs for cached app data.

To support upcoming disk usage calculation optimizations, this change
creates a new GID for each app that will be used to mark its cached
data.  We're allocating these unique GIDs so that we can use
quotactl() to track cached data on a per-app basis.

Test: builds, boots, tests pass
Bug: 27948817
Change-Id: Ic00c39ccedc23d5d43988029e9921679126f8f2d
diff --git a/libc/bionic/grp_pwd.cpp b/libc/bionic/grp_pwd.cpp
index 332b2b8..db0f777 100644
--- a/libc/bionic/grp_pwd.cpp
+++ b/libc/bionic/grp_pwd.cpp
@@ -205,10 +205,11 @@
 }
 
 // Translate a user/group name to the corresponding user/group id.
-// all_a1234 -> 0 * AID_USER + AID_SHARED_GID_START + 1234 (group name only)
-// u0_a1234 -> 0 * AID_USER + AID_APP + 1234
-// u2_i1000 -> 2 * AID_USER + AID_ISOLATED_START + 1000
-// u1_system -> 1 * AID_USER + android_ids['system']
+// all_a1234 -> 0 * AID_USER_OFFSET + AID_SHARED_GID_START + 1234 (group name only)
+// u0_a1234_cache -> 0 * AID_USER_OFFSET + AID_CACHE_GID_START + 1234 (group name only)
+// u0_a1234 -> 0 * AID_USER_OFFSET + AID_APP_START + 1234
+// u2_i1000 -> 2 * AID_USER_OFFSET + AID_ISOLATED_START + 1000
+// u1_system -> 1 * AID_USER_OFFSET + android_ids['system']
 // returns 0 and sets errno to ENOENT in case of error.
 static id_t app_id_from_name(const char* name, bool is_group) {
   char* end;
@@ -242,7 +243,13 @@
       }
     } else {
       // end will point to \0 if the strtoul below succeeds.
-      appid = strtoul(end+2, &end, 10) + AID_APP;
+      appid = strtoul(end+2, &end, 10);
+      if (is_group && !strcmp(end, "_cache")) {
+        end += 6;
+        appid += AID_CACHE_GID_START;
+      } else {
+        appid += AID_APP_START;
+      }
     }
   } else if (end[1] == 'i' && isdigit(end[2])) {
     // end will point to \0 if the strtoul below succeeds.
@@ -271,20 +278,20 @@
   }
 
   // Check that app id is within range.
-  if (appid >= AID_USER) {
+  if (appid >= AID_USER_OFFSET) {
     errno = ENOENT;
     return 0;
   }
 
-  return (appid + userid*AID_USER);
+  return (appid + userid*AID_USER_OFFSET);
 }
 
 static void print_app_name_from_uid(const uid_t uid, char* buffer, const int bufferlen) {
-  const uid_t appid = uid % AID_USER;
-  const uid_t userid = uid / AID_USER;
+  const uid_t appid = uid % AID_USER_OFFSET;
+  const uid_t userid = uid / AID_USER_OFFSET;
   if (appid >= AID_ISOLATED_START) {
     snprintf(buffer, bufferlen, "u%u_i%u", userid, appid - AID_ISOLATED_START);
-  } else if (appid < AID_APP) {
+  } else if (appid < AID_APP_START) {
     for (size_t n = 0; n < android_id_count; n++) {
       if (android_ids[n].aid == appid) {
         snprintf(buffer, bufferlen, "u%u_%s", userid, android_ids[n].name);
@@ -292,18 +299,20 @@
       }
     }
   } else {
-    snprintf(buffer, bufferlen, "u%u_a%u", userid, appid - AID_APP);
+    snprintf(buffer, bufferlen, "u%u_a%u", userid, appid - AID_APP_START);
   }
 }
 
 static void print_app_name_from_gid(const gid_t gid, char* buffer, const int bufferlen) {
-  const uid_t appid = gid % AID_USER;
-  const uid_t userid = gid / AID_USER;
+  const uid_t appid = gid % AID_USER_OFFSET;
+  const uid_t userid = gid / AID_USER_OFFSET;
   if (appid >= AID_ISOLATED_START) {
     snprintf(buffer, bufferlen, "u%u_i%u", userid, appid - AID_ISOLATED_START);
   } else if (userid == 0 && appid >= AID_SHARED_GID_START && appid <= AID_SHARED_GID_END) {
     snprintf(buffer, bufferlen, "all_a%u", appid - AID_SHARED_GID_START);
-  } else if (appid < AID_APP) {
+  } else if (appid >= AID_CACHE_GID_START && appid <= AID_CACHE_GID_END) {
+    snprintf(buffer, bufferlen, "u%u_a%u_cache", userid, appid - AID_CACHE_GID_START);
+  } else if (appid < AID_APP_START) {
     for (size_t n = 0; n < android_id_count; n++) {
       if (android_ids[n].aid == appid) {
         snprintf(buffer, bufferlen, "u%u_%s", userid, android_ids[n].name);
@@ -311,7 +320,7 @@
       }
     }
   } else {
-    snprintf(buffer, bufferlen, "u%u_a%u", userid, appid - AID_APP);
+    snprintf(buffer, bufferlen, "u%u_a%u", userid, appid - AID_APP_START);
   }
 }
 
@@ -371,21 +380,21 @@
 }
 
 // Translate a uid into the corresponding name.
-// 0 to AID_APP-1                   -> "system", "radio", etc.
-// AID_APP to AID_ISOLATED_START-1  -> u0_a1234
-// AID_ISOLATED_START to AID_USER-1 -> u0_i1234
-// AID_USER+                        -> u1_radio, u1_a1234, u2_i1234, etc.
+// 0 to AID_APP_START-1                    -> "system", "radio", etc.
+// AID_APP_START to AID_ISOLATED_START-1   -> u0_a1234
+// AID_ISOLATED_START to AID_USER_OFFSET-1 -> u0_i1234
+// AID_USER_OFFSET+                        -> u1_radio, u1_a1234, u2_i1234, etc.
 // returns a passwd structure (sets errno to ENOENT on failure).
 static passwd* app_id_to_passwd(uid_t uid, passwd_state_t* state) {
-  if (uid < AID_APP) {
+  if (uid < AID_APP_START) {
     errno = ENOENT;
     return NULL;
   }
 
   print_app_name_from_uid(uid, state->name_buffer_, sizeof(state->name_buffer_));
 
-  const uid_t appid = uid % AID_USER;
-  if (appid < AID_APP) {
+  const uid_t appid = uid % AID_USER_OFFSET;
+  if (appid < AID_APP_START) {
       snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/");
   } else {
       snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/data");
@@ -405,7 +414,7 @@
 // Translate a gid into the corresponding app_<gid>
 // group structure (sets errno to ENOENT on failure).
 static group* app_id_to_group(gid_t gid, group_state_t* state) {
-  if (gid < AID_APP) {
+  if (gid < AID_APP_START) {
     errno = ENOENT;
     return NULL;
   }
@@ -513,10 +522,10 @@
   }
 
   start = end;
-  end += AID_USER - AID_APP; // Do not expose higher users
+  end += AID_USER_OFFSET - AID_APP_START; // Do not expose higher users
 
   if (state->getpwent_idx < end) {
-    return app_id_to_passwd(state->getpwent_idx++ - start + AID_APP, state);
+    return app_id_to_passwd(state->getpwent_idx++ - start + AID_APP_START, state);
   }
 
   // We are not reporting u1_a* and higher or we will be here forever
@@ -641,11 +650,11 @@
   }
 
   start = end;
-  end += AID_USER - AID_APP; // Do not expose higher groups
+  end += AID_USER_OFFSET - AID_APP_START; // Do not expose higher groups
 
   if (state->getgrent_idx < end) {
     init_group_state(state);
-    return app_id_to_group(state->getgrent_idx++ - start + AID_APP, state);
+    return app_id_to_group(state->getgrent_idx++ - start + AID_APP_START, state);
   }
 
   // We are not reporting u1_a* and higher or we will be here forever
diff --git a/tests/grp_pwd_test.cpp b/tests/grp_pwd_test.cpp
index a684780..ed68fca 100644
--- a/tests/grp_pwd_test.cpp
+++ b/tests/grp_pwd_test.cpp
@@ -339,6 +339,22 @@
   check_get_group("u0_a9999", 19999);
 }
 
+TEST(getgrnam, app_id_u0_a0_cache) {
+  check_get_group("u0_a0_cache", 20000);
+}
+
+TEST(getgrnam, app_id_u0_a1234_cache) {
+  check_get_group("u0_a1234_cache", 21234);
+}
+
+TEST(getgrnam, app_id_u0_a9999_cache) {
+  check_get_group("u0_a9999_cache", 29999);
+}
+
+TEST(getgrnam, app_id_u10_a1234_cache) {
+  check_get_group("u10_a1234_cache", 1021234);
+}
+
 // Test the difference between uid and shared gid.
 TEST(getgrnam, app_id_all_a9999) {
   check_get_group("all_a9999", 59999);