Add truncate_timestamp annotation

Mark privacy-sensitive atoms with truncate_timestamp annotation.

Factor out annotation collation to a helper method.

Add truncate_timestamp annotation support in stats-log-api-gen.

Add writeAnnotation* calls in Java and native generated code for
atom id annotations.

TODO: remove kTruncatingTimestampAtoms from atoms_info.
TODO: use truncate_timestamp annotation inside statsd.

Bug: 151111680
Test: stats-log-api-gen-test
Test: m statslog-framework-java-gen
Test: m libstatsmetadata

Change-Id: I3db5f4ffbf959bd36c62f890cc88606912798d40
diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto
index 40a24dc..afee79d 100644
--- a/cmds/statsd/src/atom_field_options.proto
+++ b/cmds/statsd/src/atom_field_options.proto
@@ -117,4 +117,6 @@
     optional bool allow_from_any_uid = 50003 [default = false];
 
     repeated string module = 50004;
+
+    optional bool truncate_timestamp = 50005 [default = false];
 }
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index f9711c3..e60ac7f 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -93,7 +93,8 @@
                 10 [(module) = "framework", (module) = "statsdtest"];
         LongPartialWakelockStateChanged long_partial_wakelock_state_changed =
                 11 [(module) = "framework"];
-        MobileRadioPowerStateChanged mobile_radio_power_state_changed = 12 [(module) = "framework"];
+        MobileRadioPowerStateChanged mobile_radio_power_state_changed =
+                12 [(module) = "framework", (truncate_timestamp) = true];
         WifiRadioPowerStateChanged wifi_radio_power_state_changed = 13 [(module) = "framework"];
         ActivityManagerSleepStateChanged activity_manager_sleep_state_changed =
                 14 [(module) = "framework"];
@@ -106,7 +107,8 @@
                 20 [(module) = "framework", (module) = "statsdtest"];
         DeviceIdleModeStateChanged device_idle_mode_state_changed = 21 [(module) = "framework"];
         DeviceIdlingModeStateChanged device_idling_mode_state_changed = 22 [(module) = "framework"];
-        AudioStateChanged audio_state_changed = 23 [(module) = "framework"];
+        AudioStateChanged audio_state_changed =
+                23 [(module) = "framework", (truncate_timestamp) = true];
         MediaCodecStateChanged media_codec_state_changed = 24 [(module) = "framework"];
         CameraStateChanged camera_state_changed = 25 [(module) = "framework"];
         FlashlightStateChanged flashlight_state_changed = 26 [(module) = "framework"];
@@ -127,7 +129,8 @@
         WifiLockStateChanged wifi_lock_state_changed = 37 [(module) = "wifi"];
         WifiSignalStrengthChanged wifi_signal_strength_changed = 38 [(module) = "wifi"];
         WifiScanStateChanged wifi_scan_state_changed = 39 [(module) = "wifi"];
-        PhoneSignalStrengthChanged phone_signal_strength_changed = 40 [(module) = "framework"];
+        PhoneSignalStrengthChanged phone_signal_strength_changed =
+                40 [(module) = "framework", (truncate_timestamp) = true];
         SettingChanged setting_changed = 41 [(module) = "framework"];
         ActivityForegroundStateChanged activity_foreground_state_changed =
                 42 [(module) = "framework", (module) = "statsdtest"];
@@ -153,7 +156,8 @@
                 59 [(module) = "framework", (module) = "statsdtest"];
         ForegroundServiceStateChanged foreground_service_state_changed
                 = 60 [(module) = "framework"];
-        CallStateChanged call_state_changed = 61 [(module) = "telecom"];
+        CallStateChanged call_state_changed =
+                61 [(module) = "telecom", (truncate_timestamp) = true];
         KeyguardStateChanged keyguard_state_changed = 62 [(module) = "sysui"];
         KeyguardBouncerStateChanged keyguard_bouncer_state_changed = 63 [(module) = "sysui"];
         KeyguardBouncerPasswordEntered keyguard_bouncer_password_entered = 64 [(module) = "sysui"];
@@ -419,8 +423,10 @@
     oneof pulled {
         WifiBytesTransfer wifi_bytes_transfer = 10000 [(module) = "framework"];
         WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001 [(module) = "framework"];
-        MobileBytesTransfer mobile_bytes_transfer = 10002 [(module) = "framework"];
-        MobileBytesTransferByFgBg mobile_bytes_transfer_by_fg_bg = 10003 [(module) = "framework"];
+        MobileBytesTransfer mobile_bytes_transfer =
+                10002 [(module) = "framework", (truncate_timestamp) = true];
+        MobileBytesTransferByFgBg mobile_bytes_transfer_by_fg_bg =
+                10003 [(module) = "framework", (truncate_timestamp) = true];
         BluetoothBytesTransfer bluetooth_bytes_transfer = 10006 [(module) = "framework"];
         KernelWakelock kernel_wakelock = 10004 [(module) = "framework"];
         SubsystemSleepState subsystem_sleep_state = 10005 [(module) = "statsdtest"];
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 47eb63e..27cc259 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -55,7 +55,8 @@
         resetState(that.resetState),
         nested(that.nested),
         uidField(that.uidField),
-        whitelisted(that.whitelisted) {}
+        whitelisted(that.whitelisted),
+        truncateTimestamp(that.truncateTimestamp) {}
 
 AtomDecl::AtomDecl(int c, const string& n, const string& m)
     :code(c),
@@ -173,6 +174,126 @@
                 annotationId, atomDecl->code, annotationType, annotationValue));
 }
 
+static int collate_field_annotations(AtomDecl* atomDecl, const FieldDescriptor* field,
+        const int fieldNumber, const java_type_t& javaType) {
+    int errorCount = 0;
+
+    if (field->options().HasExtension(os::statsd::state_field_option)) {
+      const int option = field->options().GetExtension(os::statsd::state_field_option).option();
+      if (option != STATE_OPTION_UNSET) {
+          addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_STATE_OPTION,
+                  ANNOTATION_TYPE_INT, AnnotationValue(option));
+      }
+
+      if (option == STATE_OPTION_PRIMARY) {
+          if (javaType == JAVA_TYPE_UNKNOWN ||
+                  javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
+                  javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
+              print_error(
+                  field,
+                  "Invalid primary state field: '%s'\n",
+                  atomDecl->message.c_str());
+              errorCount++;
+          }
+          atomDecl->primaryFields.push_back(fieldNumber);
+
+      }
+
+      if (option == STATE_OPTION_PRIMARY_FIELD_FIRST_UID) {
+          if (javaType != JAVA_TYPE_ATTRIBUTION_CHAIN) {
+              print_error(
+                  field,
+                  "PRIMARY_FIELD_FIRST_UID annotation is only for AttributionChains: '%s'\n",
+                  atomDecl->message.c_str());
+              errorCount++;
+          } else {
+              atomDecl->primaryFields.push_back(FIRST_UID_IN_CHAIN_ID);
+          }
+      }
+
+      if (option == STATE_OPTION_EXCLUSIVE) {
+          if (javaType == JAVA_TYPE_UNKNOWN ||
+                  javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
+                  javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
+              print_error(
+                  field,
+                  "Invalid exclusive state field: '%s'\n",
+                  atomDecl->message.c_str());
+              errorCount++;
+          }
+
+          if (atomDecl->exclusiveField == 0) {
+              atomDecl->exclusiveField = fieldNumber;
+          } else {
+              print_error(
+                  field,
+                  "Cannot have more than one exclusive state field in an atom: '%s'\n",
+                  atomDecl->message.c_str());
+              errorCount++;
+          }
+
+          if (field->options()
+                      .GetExtension(os::statsd::state_field_option)
+                      .has_default_state_value()) {
+              const int defaultState =
+                      field->options().GetExtension(os::statsd::state_field_option)
+                      .default_state_value();
+              atomDecl->defaultState = defaultState;
+
+              addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_DEFAULT_STATE,
+                      ANNOTATION_TYPE_INT, AnnotationValue(defaultState));
+          }
+
+          if (field->options().GetExtension(os::statsd::state_field_option)
+                  .has_reset_state_value()) {
+              const int resetState = field->options()
+                      .GetExtension(os::statsd::state_field_option)
+                      .reset_state_value();
+
+              atomDecl->resetState = resetState;
+              addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_RESET_STATE,
+                      ANNOTATION_TYPE_INT, AnnotationValue(resetState));
+          }
+
+          if (field->options().GetExtension(os::statsd::state_field_option)
+                  .has_nested()) {
+              const bool nested =
+                      field->options().GetExtension(os::statsd::state_field_option).nested();
+              atomDecl->nested = nested;
+
+              addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_STATE_NESTED,
+                      ANNOTATION_TYPE_BOOL, AnnotationValue(nested));
+          }
+      }
+
+    }
+
+    if (field->options().GetExtension(os::statsd::is_uid) == true) {
+        if (javaType != JAVA_TYPE_INT) {
+            print_error(
+                field,
+                "is_uid annotation can only be applied to int32 fields: '%s'\n",
+                atomDecl->message.c_str());
+            errorCount++;
+        }
+
+        if (atomDecl->uidField == 0) {
+            atomDecl->uidField = fieldNumber;
+
+            addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_IS_UID,
+                    ANNOTATION_TYPE_BOOL, AnnotationValue(true));
+        } else {
+            print_error(
+                field,
+                "Cannot have more than one field in an atom with is_uid annotation: '%s'\n",
+                atomDecl->message.c_str());
+            errorCount++;
+        }
+    }
+
+    return errorCount;
+}
+
 /**
  * Gather the info about an atom proto.
  */
@@ -287,6 +408,12 @@
                          os::statsd::LogMode::MODE_BYTES;
 
     AtomField atField(field->name(), javaType);
+
+    if (javaType == JAVA_TYPE_ENUM) {
+      // All enums are treated as ints when it comes to function signatures.
+      collate_enums(*field->enum_type(), &atField);
+    }
+
     // Generate signature for pushed atoms
     if (atomDecl->code < PULL_ATOM_START_ID) {
       if (javaType == JAVA_TYPE_ENUM) {
@@ -298,129 +425,10 @@
           signature->push_back(javaType);
       }
     }
-    if (javaType == JAVA_TYPE_ENUM) {
-      // All enums are treated as ints when it comes to function signatures.
-      collate_enums(*field->enum_type(), &atField);
-    }
+
     atomDecl->fields.push_back(atField);
 
-    if (field->options().HasExtension(os::statsd::state_field_option)) {
-        const int option = field->options().GetExtension(os::statsd::state_field_option).option();
-        if (option != STATE_OPTION_UNSET) {
-            addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_STATE_OPTION,
-                    ANNOTATION_TYPE_INT, AnnotationValue(option));
-        }
-
-        if (option == STATE_OPTION_PRIMARY) {
-            if (javaType == JAVA_TYPE_UNKNOWN ||
-                    javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
-                    javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
-                print_error(
-                    field,
-                    "Invalid primary state field: '%s'\n",
-                    atom->name().c_str());
-                errorCount++;
-                continue;
-            }
-            atomDecl->primaryFields.push_back(it->first);
-
-        }
-
-        if (option == STATE_OPTION_PRIMARY_FIELD_FIRST_UID) {
-            if (javaType != JAVA_TYPE_ATTRIBUTION_CHAIN) {
-                print_error(
-                    field,
-                    "PRIMARY_FIELD_FIRST_UID annotation is only for AttributionChains: '%s'\n",
-                    atom->name().c_str());
-                errorCount++;
-                continue;
-            } else {
-                atomDecl->primaryFields.push_back(FIRST_UID_IN_CHAIN_ID);
-            }
-        }
-
-        if (option == STATE_OPTION_EXCLUSIVE) {
-            if (javaType == JAVA_TYPE_UNKNOWN ||
-                    javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
-                    javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
-                print_error(
-                    field,
-                    "Invalid exclusive state field: '%s'\n",
-                    atom->name().c_str());
-                errorCount++;
-                continue;
-            }
-
-            if (atomDecl->exclusiveField == 0) {
-                atomDecl->exclusiveField = it->first;
-            } else {
-                print_error(
-                    field,
-                    "Cannot have more than one exclusive state field in an atom: '%s'\n",
-                    atom->name().c_str());
-                errorCount++;
-                continue;
-            }
-
-            if (field->options()
-                        .GetExtension(os::statsd::state_field_option)
-                        .has_default_state_value()) {
-                const int defaultState =
-                        field->options().GetExtension(os::statsd::state_field_option)
-                        .default_state_value();
-                atomDecl->defaultState = defaultState;
-
-                addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_DEFAULT_STATE,
-                        ANNOTATION_TYPE_INT, AnnotationValue(defaultState));
-            }
-
-            if (field->options().GetExtension(os::statsd::state_field_option)
-                    .has_reset_state_value()) {
-                const int resetState = field->options()
-                        .GetExtension(os::statsd::state_field_option)
-                        .reset_state_value();
-
-                atomDecl->resetState = resetState;
-                addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_RESET_STATE,
-                        ANNOTATION_TYPE_INT, AnnotationValue(resetState));
-            }
-
-            if (field->options().GetExtension(os::statsd::state_field_option)
-                    .has_nested()) {
-                const bool nested =
-                        field->options().GetExtension(os::statsd::state_field_option).nested();
-                atomDecl->nested = nested;
-
-                addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_STATE_NESTED,
-                        ANNOTATION_TYPE_BOOL, AnnotationValue(nested));
-            }
-        }
-
-    }
-    if (field->options().GetExtension(os::statsd::is_uid) == true) {
-        if (javaType != JAVA_TYPE_INT) {
-            print_error(
-                field,
-                "is_uid annotation can only be applied to int32 fields: '%s'\n",
-                atom->name().c_str());
-            errorCount++;
-            continue;
-        }
-
-        if (atomDecl->uidField == 0) {
-            atomDecl->uidField = it->first;
-
-            addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_IS_UID,
-                    ANNOTATION_TYPE_BOOL, AnnotationValue(true));
-        } else {
-            print_error(
-                field,
-                "Cannot have more than one field in an atom with is_uid annotation: '%s'\n",
-                atom->name().c_str());
-            errorCount++;
-            continue;
-        }
-    }
+    errorCount += collate_field_annotations(atomDecl, field, it->first, javaType);
   }
 
   return errorCount;
@@ -537,6 +545,18 @@
 
     if (atomField->options().GetExtension(os::statsd::allow_from_any_uid) == true) {
         atomDecl.whitelisted = true;
+        if (dbg) {
+            printf("%s is whitelisted\n", atomField->name().c_str());
+        }
+    }
+
+    if (atomDecl.code < PULL_ATOM_START_ID
+            && atomField->options().GetExtension(os::statsd::truncate_timestamp)) {
+        addAnnotationToAtomDecl(&atomDecl, ATOM_ID_FIELD_NUMBER, ANNOTATION_ID_TRUNCATE_TIMESTAMP,
+                ANNOTATION_TYPE_BOOL, AnnotationValue(true));
+        if (dbg) {
+            printf("%s can have timestamp truncated\n", atomField->name().c_str());
+        }
     }
 
     vector<java_type_t> signature;
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index c6dad1d..be5966c 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -52,6 +52,8 @@
 const int STATE_OPTION_PRIMARY_FIELD_FIRST_UID = os::statsd::StateField::PRIMARY_FIELD_FIRST_UID;
 const int STATE_OPTION_PRIMARY = os::statsd::StateField::PRIMARY_FIELD;
 
+const int ATOM_ID_FIELD_NUMBER = -1;
+
 const string DEFAULT_MODULE_NAME = "DEFAULT";
 
 /**
@@ -147,6 +149,8 @@
 
     bool whitelisted = false;
 
+    bool truncateTimestamp = false;
+
     AtomDecl();
     AtomDecl(const AtomDecl& that);
     AtomDecl(int code, const string& name, const string& message);
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index 18508d2..1a7efba 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -121,6 +121,7 @@
 
         // Write atom code.
         fprintf(out, "%s        builder.setAtomId(code);\n", indent.c_str());
+        write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAnnotations);
 
         // Write the args.
         argIndex = 1;
diff --git a/tools/stats_log_api_gen/native_writer.cpp b/tools/stats_log_api_gen/native_writer.cpp
index 90dcae4..b171f0e 100644
--- a/tools/stats_log_api_gen/native_writer.cpp
+++ b/tools/stats_log_api_gen/native_writer.cpp
@@ -82,6 +82,7 @@
         if (supportQ) {
             fprintf(out, "    StatsEventCompat event;\n");
             fprintf(out, "    event.setAtomId(code);\n");
+            write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAnnotations, "event.", "");
             for (vector<java_type_t>::const_iterator arg = signature.begin();
                     arg != signature.end(); arg++) {
                 switch (*arg) {
@@ -124,6 +125,8 @@
         } else {
             fprintf(out, "    AStatsEvent* event = AStatsEvent_obtain();\n");
             fprintf(out, "    AStatsEvent_setAtomId(event, code);\n");
+            write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAnnotations, "AStatsEvent_",
+                    "event, ");
             for (vector<java_type_t>::const_iterator arg = signature.begin();
                     arg != signature.end(); arg++) {
                 switch (*arg) {