Add logging for user permission interactions.

bug:21078221

Change-Id: Ie5bfb4c6013faf528b95eda0d5caf1c591f1e439
diff --git a/src/com/android/packageinstaller/permission/model/Permission.java b/src/com/android/packageinstaller/permission/model/Permission.java
index 388ae75..09c927b 100644
--- a/src/com/android/packageinstaller/permission/model/Permission.java
+++ b/src/com/android/packageinstaller/permission/model/Permission.java
@@ -44,6 +44,10 @@
         return mAppOp;
     }
 
+    public int getFlags() {
+        return mFlags;
+    }
+
     public boolean hasAppOp() {
         return mAppOp != AppOpsManager.OP_NONE;
     }
diff --git a/src/com/android/packageinstaller/permission/model/PermissionApps.java b/src/com/android/packageinstaller/permission/model/PermissionApps.java
index 81e5af5..d3d46cf 100644
--- a/src/com/android/packageinstaller/permission/model/PermissionApps.java
+++ b/src/com/android/packageinstaller/permission/model/PermissionApps.java
@@ -106,12 +106,14 @@
     }
 
     public static class PermissionApp implements Comparable<PermissionApp> {
+        private final String mPackageName;
         private final PermissionGroup mPermissionGroup;
         private final String mLabel;
         private final Drawable mIcon;
 
-        public PermissionApp(PermissionGroup permissionGroup, String label,
-                Drawable icon) {
+        public PermissionApp(String packageName, PermissionGroup permissionGroup,
+                String label, Drawable icon) {
+            mPackageName = packageName;
             mPermissionGroup = permissionGroup;
             mLabel = label;
             mIcon = icon;
@@ -149,6 +151,14 @@
             return mPermissionGroup.isSystemFixed();
         }
 
+        public String getPackageName() {
+            return mPackageName;
+        }
+
+        public PermissionGroup getPermissionGroup() {
+            return mPermissionGroup;
+        }
+
         @Override
         public int compareTo(PermissionApp another) {
             final int result = mLabel.compareTo(another.mLabel);
@@ -209,8 +219,8 @@
                         PermissionGroup group = PermissionGroup.create(mContext,
                                 app, groupInfo, groupPermInfos);
 
-                        PermissionApp permApp = new PermissionApp(group,
-                                app.applicationInfo.loadLabel(mPm).toString(),
+                        PermissionApp permApp = new PermissionApp(app.packageName,
+                                group, app.applicationInfo.loadLabel(mPm).toString(),
                                 getBadgedIcon(app.applicationInfo));
 
                         permApps.add(permApp);
diff --git a/src/com/android/packageinstaller/permission/model/PermissionGroup.java b/src/com/android/packageinstaller/permission/model/PermissionGroup.java
index 1f20e44..9e90d4f 100644
--- a/src/com/android/packageinstaller/permission/model/PermissionGroup.java
+++ b/src/com/android/packageinstaller/permission/model/PermissionGroup.java
@@ -402,6 +402,16 @@
         return new ArrayList<>(mPermissions.values());
     }
 
+    public int getFlags() {
+        int flags = 0;
+        final int permissionCount = mPermissions.size();
+        for (int i = 0; i < permissionCount; i++) {
+            Permission permission = mPermissions.valueAt(i);
+            flags |= permission.getFlags();
+        }
+        return flags;
+    }
+
     public boolean isUserFixed() {
         final int permissionCount = mPermissions.size();
         for (int i = 0; i < permissionCount; i++) {
diff --git a/src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java b/src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java
index 7b64d7b..a7c404c 100644
--- a/src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/AppPermissionsFragment.java
@@ -49,8 +49,12 @@
 import com.android.packageinstaller.R;
 import com.android.packageinstaller.permission.model.AppPermissions;
 import com.android.packageinstaller.permission.model.PermissionGroup;
+import com.android.packageinstaller.permission.utils.SafetyNetLogger;
 import com.android.packageinstaller.permission.utils.Utils;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public final class AppPermissionsFragment extends SettingsWithHeader
         implements OnPreferenceChangeListener {
 
@@ -60,6 +64,7 @@
 
     private static final String EXTRA_HIDE_INFO_BUTTON = "hideInfoButton";
 
+    private List<PermissionGroup> mToggledGroups;
     private AppPermissions mAppPermissions;
     private PreferenceScreen mExtraScreen;
 
@@ -222,6 +227,8 @@
             return false;
         }
 
+        addToggledGroup(group);
+
         if (newValue == Boolean.TRUE) {
             group.grantRuntimePermissions(false);
         } else {
@@ -248,6 +255,32 @@
         return true;
     }
 
+    @Override
+    public void onPause() {
+        super.onPause();
+        logToggledGroups();
+    }
+
+    private void addToggledGroup(PermissionGroup group) {
+        if (mToggledGroups == null) {
+            mToggledGroups = new ArrayList<>();
+        }
+        // Double toggle is back to initial state.
+        if (mToggledGroups.contains(group)) {
+            mToggledGroups.remove(group);
+        } else {
+            mToggledGroups.add(group);
+        }
+    }
+
+    private void logToggledGroups() {
+        if (mToggledGroups != null) {
+            String packageName = mAppPermissions.getPackageInfo().packageName;
+            SafetyNetLogger.logPermissionsToggled(packageName, mToggledGroups);
+            mToggledGroups = null;
+        }
+    }
+
     private void updateUi() {
         mAppPermissions.refresh();
 
diff --git a/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java b/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
index 9ed47df..b406db1 100644
--- a/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
+++ b/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
@@ -37,6 +37,10 @@
 import com.android.packageinstaller.permission.model.AppPermissions;
 import com.android.packageinstaller.permission.model.Permission;
 import com.android.packageinstaller.permission.model.PermissionGroup;
+import com.android.packageinstaller.permission.utils.SafetyNetLogger;
+
+import java.util.ArrayList;
+import java.util.List;
 
 public class GrantPermissionsActivity extends Activity implements
         GrantPermissionViewHandler.OnRequestGrantPermissionGroupResult {
@@ -289,6 +293,7 @@
     }
 
     private void setResultAndFinish() {
+        logRequestedPermissionGroups();
         Intent result = new Intent(PackageManager.ACTION_REQUEST_PERMISSIONS);
         result.putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES, mRequestedPermissions);
         result.putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_RESULTS, mGrantResults);
@@ -296,6 +301,20 @@
         finish();
     }
 
+    private void logRequestedPermissionGroups() {
+        if (mRequestGrantPermissionGroups.isEmpty()) {
+            return;
+        }
+
+        final int groupCount = mRequestGrantPermissionGroups.size();
+        List<PermissionGroup> groups = new ArrayList<>(groupCount);
+        for (int i = 0; i < groupCount; i++) {
+            groups.add(mRequestGrantPermissionGroups.valueAt(i).mGroup);
+        }
+
+        SafetyNetLogger.logPermissionsRequested(mAppPermissions.getPackageInfo(), groups);
+    }
+
     private static final class GroupState {
         public static final int STATE_UNKNOWN = 0;
         public static final int STATE_ALLOWED = 1;
diff --git a/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java b/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java
index f18acfe..dae90b9 100644
--- a/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java
+++ b/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java
@@ -25,6 +25,7 @@
 import android.preference.Preference.OnPreferenceChangeListener;
 import android.preference.PreferenceScreen;
 import android.preference.SwitchPreference;
+import android.support.v4.util.ArrayMap;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.View;
@@ -36,6 +37,11 @@
 import com.android.packageinstaller.permission.model.PermissionApps;
 import com.android.packageinstaller.permission.model.PermissionApps.Callback;
 import com.android.packageinstaller.permission.model.PermissionApps.PermissionApp;
+import com.android.packageinstaller.permission.model.PermissionGroup;
+import com.android.packageinstaller.permission.utils.SafetyNetLogger;
+
+import java.util.ArrayList;
+import java.util.List;
 
 public final class PermissionAppsFragment extends SettingsWithHeader implements Callback,
         OnPreferenceChangeListener {
@@ -50,6 +56,8 @@
 
     private PermissionApps mPermissionApps;
 
+    private ArrayMap<String, PermissionGroup> mToggledGroups;
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -156,6 +164,8 @@
         String pkg = preference.getKey();
         PermissionApp app = mPermissionApps.getApp(pkg);
 
+        addToggledGroup(app.getPackageName(), app.getPermissionGroup());
+
         if (app == null) {
             return false;
         }
@@ -167,4 +177,34 @@
         return true;
     }
 
+    @Override
+    public void onPause() {
+        super.onPause();
+        logToggledGroups();
+    }
+
+    private void addToggledGroup(String packageName, PermissionGroup group) {
+        if (mToggledGroups == null) {
+            mToggledGroups = new ArrayMap<>();
+        }
+        // Double toggle is back to initial state.
+        if (mToggledGroups.containsKey(packageName)) {
+            mToggledGroups.remove(packageName);
+        } else {
+            mToggledGroups.put(packageName, group);
+        }
+    }
+
+    private void logToggledGroups() {
+        if (mToggledGroups != null) {
+            final int groupCount = mToggledGroups.size();
+            for (int i = 0; i < groupCount; i++) {
+                String packageName = mToggledGroups.keyAt(i);
+                List<PermissionGroup> groups = new ArrayList<>();
+                groups.add(mToggledGroups.valueAt(i));
+                SafetyNetLogger.logPermissionsToggled(packageName, groups);
+            }
+            mToggledGroups = null;
+        }
+    }
 }
diff --git a/src/com/android/packageinstaller/permission/utils/SafetyNetLogger.java b/src/com/android/packageinstaller/permission/utils/SafetyNetLogger.java
new file mode 100644
index 0000000..0163b75
--- /dev/null
+++ b/src/com/android/packageinstaller/permission/utils/SafetyNetLogger.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.packageinstaller.permission.utils;
+
+import android.content.pm.PackageInfo;
+import android.util.EventLog;
+import com.android.packageinstaller.permission.model.PermissionGroup;
+
+import java.util.List;
+
+public final class SafetyNetLogger {
+
+    // The log tag used by SafetyNet to pick entries from the event log.
+    private static final int SNET_NET_EVENT_LOG_TAG = 0x534e4554;
+
+    // Log tag for the result of permissions request.
+    private static final String PERMISSIONS_REQUESTED = "permissions_requested";
+
+    // Log tag for the result of permissions toggling.
+    private static final String PERMISSIONS_TOGGLED = "permissions_toggled";
+
+    private SafetyNetLogger() {
+        /* do nothing */
+    }
+
+    public static void logPermissionsRequested(PackageInfo packageInfo,
+            List<PermissionGroup> groups) {
+        EventLog.writeEvent(SNET_NET_EVENT_LOG_TAG, PERMISSIONS_REQUESTED,
+                packageInfo.applicationInfo.uid, buildChangedGroupForPackageMessage(
+                        packageInfo.packageName, groups));
+    }
+
+    public static void logPermissionsToggled(String packageName, List<PermissionGroup> groups) {
+        EventLog.writeEvent(SNET_NET_EVENT_LOG_TAG, PERMISSIONS_TOGGLED,
+                android.os.Process.myUid(), buildChangedGroupForPackageMessage(
+                        packageName, groups));
+    }
+
+    private static String buildChangedGroupForPackageMessage(String packageName,
+            List<PermissionGroup> groups) {
+        StringBuilder builder = new StringBuilder();
+
+        builder.append(packageName).append(':');
+
+        final int groupCount = groups.size();
+        for (int i = 0; i < groupCount; i++) {
+            PermissionGroup group = groups.get(i);
+            if (i > 0) {
+                builder.append(';');
+            }
+            builder.append(group.getName()).append('|');
+            builder.append(group.areRuntimePermissionsGranted()).append('|');
+            builder.append(group.getFlags());
+        }
+
+        return builder.toString();
+    }
+}