CameraServiceProxy: Log camera usage metrics

- Add new events for camera usage by camera facing
- Dump stored camera events into metrics logs
- Shuffle event ordering for privacy
- Limit history to 100 entries at most

Test: Verify event log collection includes camera events
Bug: 32449509
Change-Id: I2e80b84f9bba3691893dca653ac085fef0b6c98c
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 78d593e..d6ca23f 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -138,6 +138,18 @@
     REASON_TIMEOUT = 19;
   }
 
+  // Subtypes of camera events for ACTION_CAMERA_EVENT
+  enum CameraEvent {
+    // A back-facing camera was used
+    CAMERA_BACK_USED = 0;
+
+    // A front-facing camera was used
+    CAMERA_FRONT_USED = 1;
+
+    // An external camera was used
+    CAMERA_EXTERNAL_USED = 2;
+  }
+
   // Known visual elements: views or controls.
   enum View {
     // Unknown view
@@ -4196,6 +4208,12 @@
     // OS: O DR
     DIALOG_BLUETOOTH_PAIRED_DEVICE_FORGET = 1031;
 
+    // An event from the camera service
+    // CATEGORY: OTHER
+    //  SUBTYPE: CameraEvent
+    // OS: O DR
+    ACTION_CAMERA_EVENT = 1032;
+
     // ---- End O-DR1 Constants, all O-DR1 constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 4cb7729..3133a51 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -21,6 +21,7 @@
 import android.content.IntentFilter;
 import android.hardware.ICameraService;
 import android.hardware.ICameraServiceProxy;
+import android.metrics.LogMaker;
 import android.nfc.INfcAdapter;
 import android.os.Binder;
 import android.os.Handler;
@@ -35,12 +36,15 @@
 import android.util.ArraySet;
 import android.util.Slog;
 
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -70,6 +74,9 @@
 
     private static final int RETRY_DELAY_TIME = 20; //ms
 
+    // Maximum entries to keep in usage history before dumping out
+    private static final int MAX_USAGE_HISTORY = 100;
+
     private final Context mContext;
     private final ServiceThread mHandlerThread;
     private final Handler mHandler;
@@ -83,7 +90,7 @@
 
     private final ArrayMap<String, CameraUsageEvent> mActiveCameraUsage = new ArrayMap<>();
     private final List<CameraUsageEvent> mCameraUsageHistory = new ArrayList<>();
-
+    private final MetricsLogger mLogger = new MetricsLogger();
     private static final String NFC_NOTIFICATION_PROP = "ro.camera.notify_nfc";
     private static final String NFC_SERVICE_BINDER_NAME = "nfc";
     private static final IBinder nfcInterfaceToken = new Binder();
@@ -260,13 +267,34 @@
      */
     void dumpUsageEvents() {
         synchronized(mLock) {
+            // Randomize order of events so that it's not meaningful
+            Collections.shuffle(mCameraUsageHistory);
             for (CameraUsageEvent e : mCameraUsageHistory) {
                 if (DEBUG) {
                     Slog.v(TAG, "Camera: " + e.mClientName + " used a camera facing " +
                             cameraFacingToString(e.mCameraFacing) + " for " +
                             e.getDuration() + " ms");
                 }
-                // TODO: Add event logging here
+                int subtype = 0;
+                switch(e.mCameraFacing) {
+                    case ICameraServiceProxy.CAMERA_FACING_BACK:
+                        subtype = MetricsEvent.CAMERA_BACK_USED;
+                        break;
+                    case ICameraServiceProxy.CAMERA_FACING_FRONT:
+                        subtype = MetricsEvent.CAMERA_FRONT_USED;
+                        break;
+                    case ICameraServiceProxy.CAMERA_FACING_EXTERNAL:
+                        subtype = MetricsEvent.CAMERA_EXTERNAL_USED;
+                        break;
+                    default:
+                        continue;
+                }
+                LogMaker l = new LogMaker(MetricsEvent.ACTION_CAMERA_EVENT)
+                        .setType(MetricsEvent.TYPE_ACTION)
+                        .setSubtype(subtype)
+                        .setLatency(e.getDuration())
+                        .setPackageName(e.mClientName);
+                mLogger.write(l);
             }
             mCameraUsageHistory.clear();
         }
@@ -362,6 +390,9 @@
                     if (doneEvent != null) {
                         doneEvent.markCompleted();
                         mCameraUsageHistory.add(doneEvent);
+                        if (mCameraUsageHistory.size() > MAX_USAGE_HISTORY) {
+                            dumpUsageEvents();
+                        }
                     }
                     break;
             }