Merge "Reducing amount of files created in dropbox for keystore" am: 60f9053686
am: cca1a25e53

Change-Id: Iac53d2afdb19ed8e2e9d76a68985959b68417b79
diff --git a/keystore/operation.cpp b/keystore/operation.cpp
index 07f9d6c..71ab340 100644
--- a/keystore/operation.cpp
+++ b/keystore/operation.cpp
@@ -63,7 +63,7 @@
     if (entry == mMap.end()) return {};
 
     auto op = entry->second;
-    uploadOpAsProto(*op, wasSuccessful);
+    operationUploader.uploadOpAsProto(*op, wasSuccessful);
     mMap.erase(entry);
 
     auto lruEntry = std::find(mLru.begin(), mLru.end(), token);
diff --git a/keystore/operation.h b/keystore/operation.h
index efe791f..e0865a4 100644
--- a/keystore/operation.h
+++ b/keystore/operation.h
@@ -70,6 +70,7 @@
     std::list<sp<IBinder>> mLru;
     std::map<sp<IBinder>, std::vector<sp<IBinder>>> mAppTokenMap;
     IBinder::DeathRecipient* mDeathRecipient;
+    OperationProtoHandler operationUploader;
 };
 
 }  // namespace keystore
diff --git a/keystore/operation_config.proto b/keystore/operation_config.proto
index 37b4cbb..efbb4fe 100644
--- a/keystore/operation_config.proto
+++ b/keystore/operation_config.proto
@@ -20,6 +20,7 @@
 
 option optimize_for = LITE_RUNTIME;
 
+// A single operation config
 message OperationConfig {
   // What type of encryption algorithm is the key being used in the op for.
   optional string algorithm = 1;
@@ -61,3 +62,16 @@
   // Standalone or is a file system required
   optional string key_blob_usage_reqs = 12;
 }
+
+message OperationConfigEvent {
+  optional OperationConfig op_config = 1;
+
+  // counts corresponds to the number of times each op_config in the above array
+  // was recorded during the collection period.
+  optional uint32 count = 2;
+}
+
+message OperationConfigEvents {
+    repeated OperationConfigEvent op_config_events = 1;
+}
+
diff --git a/keystore/operation_proto_handler.cpp b/keystore/operation_proto_handler.cpp
index 992232d..1833acb 100644
--- a/keystore/operation_proto_handler.cpp
+++ b/keystore/operation_proto_handler.cpp
@@ -25,10 +25,12 @@
 #include <utils/String16.h>
 #include <utils/StrongPointer.h>
 
-#include "operation_config.pb.h"
+using namespace std::chrono;
 
 namespace keystore {
 
+constexpr auto kCollectionTime = 1h;
+
 void determinePurpose(KeyPurpose purpose, OperationConfig* operationConfig) {
     switch (purpose) {
     case KeyPurpose::VERIFY:
@@ -103,19 +105,42 @@
     }
 }
 
-void uploadOpAsProto(Operation& op, bool wasOpSuccessful) {
+void OperationProtoHandler::uploadOpAsProto(Operation& op, bool wasOpSuccessful) {
     OperationConfig operationConfig;
     determinePurpose(op.purpose, &operationConfig);
     checkKeyCharacteristics(op.characteristics.softwareEnforced, &operationConfig);
     checkKeyCharacteristics(op.characteristics.hardwareEnforced, &operationConfig);
     checkOpCharacteristics(op.params, &operationConfig);
-    android::sp<android::os::DropBoxManager> dropbox(new android::os::DropBoxManager);
     operationConfig.set_was_op_successful(wasOpSuccessful);
+    // Only bother with counting an hour out when an operation entry is actually
+    // added
+    if (protoMap.empty()) {
+        start_time = std::chrono::steady_clock::now();
+    }
+    auto cur_time = std::chrono::steady_clock::now();
 
-    size_t size = operationConfig.ByteSize();
-    auto data = std::make_unique<uint8_t[]>(size);
-    operationConfig.SerializeWithCachedSizesToArray(data.get());
-    dropbox->addData(android::String16("keymaster"), data.get(), size, 0);
+    // Add operations to a map within the time duration of an hour. Deduplicate
+    // repeated ops by incrementing the counter of the original one stored and
+    // discarding the new one.
+    protoMap[operationConfig.SerializeAsString()]++;
+
+    if (cur_time - start_time >= kCollectionTime) {
+        // Iterate through the unordered map and dump all the operation protos
+        // accumulated over the hour into the holding list proto after setting
+        // their counts.
+        OperationConfigEvents opConfigEvents;
+        for (auto elem : protoMap) {
+            OperationConfigEvent* event = opConfigEvents.add_op_config_events();
+            event->mutable_op_config()->ParseFromString(elem.first);
+            event->set_count(elem.second);
+        }
+        android::sp<android::os::DropBoxManager> dropbox(new android::os::DropBoxManager);
+        size_t size = opConfigEvents.ByteSize();
+        auto data = std::make_unique<uint8_t[]>(size);
+        opConfigEvents.SerializeWithCachedSizesToArray(data.get());
+        dropbox->addData(android::String16("keymaster"), data.get(), size, 0);
+        protoMap.clear();
+    }
 }
 
 }  // namespace keystore
diff --git a/keystore/operation_proto_handler.h b/keystore/operation_proto_handler.h
index bf461b4..838f3ec 100644
--- a/keystore/operation_proto_handler.h
+++ b/keystore/operation_proto_handler.h
@@ -17,14 +17,25 @@
 #ifndef KEYSTORE_OPERATION_PROTO_HANDLER_H_
 #define KEYSTORE_OPERATION_PROTO_HANDLER_H_
 
+#include "operation_config.pb.h"
 #include "operation_struct.h"
+#include <chrono>
+#include <unordered_map>
+#include <vector>
 
 namespace keystore {
 
 using ::android::IBinder;
 using keymaster::support::Keymaster;
 
-void uploadOpAsProto(Operation& op, bool wasOpSuccessful);
+class OperationProtoHandler {
+  public:
+    void uploadOpAsProto(Operation& op, bool wasOpSuccessful);
+
+  private:
+    std::unordered_map<std::string, int> protoMap;
+    std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now();
+};
 
 }  // namespace keystore