Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f235a558 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Use multi-field logs to log permissions"

parents 068bf291 6fc35c06
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import android.view.View;
import android.view.Window;
import android.view.WindowManager;

import com.android.internal.logging.nano.MetricsProto;
import com.android.packageinstaller.DeviceUtils;
import com.android.packageinstaller.R;
import com.android.packageinstaller.permission.model.AppPermissionGroup;
@@ -219,7 +220,8 @@ public class GrantPermissionsActivity extends OverlayTouchActivity
            for (int permissionNum = 0; permissionNum < numRequestedPermissions; permissionNum++) {
                String permission = mRequestedPermissions[permissionNum];

                EventLogger.logPermissionRequested(this, permission,
                EventLogger.logPermission(
                        MetricsProto.MetricsEvent.ACTION_PERMISSION_REQUESTED, permission,
                        mAppPermissions.getPackageInfo().packageName);
            }
        }
@@ -333,7 +335,8 @@ public class GrantPermissionsActivity extends OverlayTouchActivity
                    String permission = mRequestedPermissions[i];

                    if (groupState.mGroup.hasPermission(permission)) {
                        EventLogger.logPermissionDenied(this, permission,
                        EventLogger.logPermission(
                                MetricsProto.MetricsEvent.ACTION_PERMISSION_DENIED, permission,
                                mAppPermissions.getPackageInfo().packageName);
                    }
                }
+10 −111
Original line number Diff line number Diff line
@@ -16,129 +16,28 @@

package com.android.packageinstaller.permission.utils;

import android.Manifest;
import android.app.AppOpsManager;
import android.content.Context;
import android.os.SystemProperties;
import android.metrics.LogMaker;
import android.support.annotation.NonNull;
import android.util.Log;

import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;

import java.util.Arrays;
import java.util.List;

/**
 * For each permission there are four events. The events are in the order of
 * #ALL_DANGEROUS_PERMISSIONS. The four events per permission are (in that order): "requested",
 * "granted", "denied", and "revoked".
 */
public class EventLogger {
    private static final String LOG_TAG = EventLogger.class.getSimpleName();

    /** All dangerous permission names in the same order as the events in MetricsEvent */
    private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList(
            Manifest.permission.READ_CALENDAR,
            Manifest.permission.WRITE_CALENDAR,
            Manifest.permission.CAMERA,
            Manifest.permission.READ_CONTACTS,
            Manifest.permission.WRITE_CONTACTS,
            Manifest.permission.GET_ACCOUNTS,
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.RECORD_AUDIO,
            Manifest.permission.READ_PHONE_STATE,
            Manifest.permission.CALL_PHONE,
            Manifest.permission.READ_CALL_LOG,
            Manifest.permission.WRITE_CALL_LOG,
            Manifest.permission.ADD_VOICEMAIL,
            Manifest.permission.USE_SIP,
            Manifest.permission.PROCESS_OUTGOING_CALLS,
            Manifest.permission.READ_CELL_BROADCASTS,
            Manifest.permission.BODY_SENSORS,
            Manifest.permission.SEND_SMS,
            Manifest.permission.RECEIVE_SMS,
            Manifest.permission.READ_SMS,
            Manifest.permission.RECEIVE_WAP_PUSH,
            Manifest.permission.RECEIVE_MMS,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_PHONE_NUMBERS,
            Manifest.permission.ANSWER_PHONE_CALLS);

    private static final List<String> ALL_APPOP_PERMISSIONS = Arrays.asList(
            Manifest.permission.ACCESS_NOTIFICATIONS,
            Manifest.permission.SYSTEM_ALERT_WINDOW,
            Manifest.permission.WRITE_SETTINGS,
            Manifest.permission.REQUEST_INSTALL_PACKAGES);

    /**
     * Get the first event id for the permission.
     *
     * <p>There are four events for each permission: <ul>
     *     <li>Request permission: first id + 0</li>
     *     <li>Grant permission: first id + 1</li>
     *     <li>Request for permission denied: first id + 2</li>
     *     <li>Revoke permission: first id + 3</li>
     * </ul></p>
     *
     * @param name name of the permission
     *
     * @return The first event id for the permission
     */
    private static int getBaseEventId(@NonNull String name) {
        int permIndex = ALL_DANGEROUS_PERMISSIONS.indexOf(name);

        if (permIndex != -1) {
            return MetricsEvent.ACTION_PERMISSION_REQUEST_READ_CALENDAR + permIndex * 4;
        } else {
            int appOpIndex = ALL_APPOP_PERMISSIONS.indexOf(name);

            if (appOpIndex != -1) {
                return MetricsEvent.ACTION_APPOP_REQUEST_ACCESS_NOTIFICATIONS + appOpIndex * 4;
            } else {
                if (AppOpsManager.permissionToOpCode(name) == AppOpsManager.OP_NONE
                        || "user".equals(SystemProperties.get("ro.build.type"))) {
                    Log.i(LOG_TAG, "Unknown permission " + name);

                    return MetricsEvent.ACTION_PERMISSION_REQUEST_UNKNOWN;
                } else {
                    // Most likely #ALL_DANGEROUS_PERMISSIONS or #ALL_APPOP_PERMISSIONS needs to be
                    // updated.
                    //
                    // Also update
                    // - metrics_constants.proto
                    // and most likely:
                    // - PackageManagerService#ALL_DANGEROUS_PERMISSIONS
                    throw new IllegalStateException("Unknown permission " + name);
                }
            }
        }
    }
    private static final MetricsLogger sMetricsLogger = new MetricsLogger();

    /**
     * Log that a permission was requested.
     * Log that a permission was requested/denied.
     *
     * @param context Context of the caller
     * @param action the action performed
     * @param name name of the permission
     * @param packageName package permission if for
     * @param packageName package permission is for
     */
    public static void logPermissionRequested(@NonNull Context context, @NonNull String name,
    public static void logPermission(int action, @NonNull String name,
            @NonNull String packageName) {
        MetricsLogger.action(context, getBaseEventId(name), packageName);
    }
        final LogMaker log = new LogMaker(action);
        log.setPackageName(packageName);
        log.addTaggedData(MetricsEvent.FIELD_PERMISSION, name);

    /**
     * Log that a permission request was denied.
     *
     * @param context Context of the caller
     * @param name name of the permission
     * @param packageName package permission if for
     */
    public static void logPermissionDenied(@NonNull Context context, @NonNull String name,
            @NonNull String packageName) {
        MetricsLogger.action(context, getBaseEventId(name) + 2, packageName);
        sMetricsLogger.write(log);
    }

}

tests/Android.mk

deleted100644 → 0
+0 −37
Original line number Diff line number Diff line
#############################################
# PackageInstaller Robolectric test target. #
#############################################
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES := $(call all-java-files-under, src)

LOCAL_JAVA_LIBRARIES := \
    junit \
    platform-robolectric-prebuilt \
    telephony-common

LOCAL_INSTRUMENTATION_FOR := PackageInstaller
LOCAL_MODULE := PackageInstallerRoboTests

LOCAL_MODULE_TAGS := optional

include $(BUILD_STATIC_JAVA_LIBRARY)

#############################################################
# PackageInstaller runner target to run the previous target. #
#############################################################
include $(CLEAR_VARS)

LOCAL_MODULE := RunPackageInstallerRoboTests

LOCAL_SDK_VERSION := current

LOCAL_STATIC_JAVA_LIBRARIES := \
    PackageInstallerRoboTests

LOCAL_TEST_PACKAGE := PackageInstaller

LOCAL_ROBOTEST_FAILURE_FATAL := true

include prebuilts/misc/common/robolectric/run_robotests.mk
+0 −128
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import android.Manifest;

import com.android.internal.logging.nano.MetricsProto;
import com.android.packageinstaller.shadows.ShadowMetricsLogger;
import com.android.packageinstaller.shadows.ShadowSystemProperties;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

/**
 * Tests {@link com.android.packageinstaller.permission.utils.EventLogger}
 */
@RunWith(RobolectricTestRunner.class)
@Config(manifest = "packages/apps/PackageInstaller/AndroidManifest.xml",
        shadows = {ShadowMetricsLogger.class, ShadowSystemProperties.class},
        sdk = 23)
public class EventLoggerTest {
    @Before
    public void setUp() {
        ShadowSystemProperties.setUserBuild(true);
        ShadowMetricsLogger.clearLogs();
    }

    @Test
    public void testValidRequested() {
        EventLogger.logPermissionRequested(null, Manifest.permission.READ_CALENDAR,
                "testPackage");

        assertEquals(1, ShadowMetricsLogger.getLogs().size());
        assertTrue(ShadowMetricsLogger.getLogs().contains(
                new ShadowMetricsLogger.Log(null,
                        MetricsProto.MetricsEvent.ACTION_PERMISSION_REQUEST_READ_CALENDAR,
                        "testPackage")));
    }

    @Test
    public void testValidAppOpRequested() {
        EventLogger.logPermissionRequested(null, Manifest.permission.SYSTEM_ALERT_WINDOW,
                "testPackage");

        assertEquals(1, ShadowMetricsLogger.getLogs().size());
        assertTrue(ShadowMetricsLogger.getLogs().contains(
                new ShadowMetricsLogger.Log(null,
                        MetricsProto.MetricsEvent.ACTION_APPOP_REQUEST_SYSTEM_ALERT_WINDOW,
                        "testPackage")));
    }

    @Test
    public void testValidDenied() {
        EventLogger.logPermissionDenied(null, Manifest.permission.READ_CALENDAR, "testPackage");

        assertEquals(1, ShadowMetricsLogger.getLogs().size());
        assertTrue(ShadowMetricsLogger.getLogs().contains(
                new ShadowMetricsLogger.Log(null,
                        MetricsProto.MetricsEvent.ACTION_PERMISSION_REQUEST_READ_CALENDAR + 2,
                        "testPackage")));
    }

    @Test
    public void testInvalidRequestedEngBuild() throws Throwable {
        ShadowSystemProperties.setUserBuild(false);
        EventLogger.logPermissionRequested(null, "invalid", "testPackage");

        assertEquals(1, ShadowMetricsLogger.getLogs().size());
        assertTrue(ShadowMetricsLogger.getLogs().contains(
                new ShadowMetricsLogger.Log(null,
                        MetricsProto.MetricsEvent.ACTION_PERMISSION_REQUEST_UNKNOWN,
                        "testPackage")));
    }

    @Test
    public void testInvalidDeniedEngBuild() throws Throwable {
        ShadowSystemProperties.setUserBuild(false);
        EventLogger.logPermissionRequested(null, "invalid", "testPackage");

        assertEquals(1, ShadowMetricsLogger.getLogs().size());
        assertTrue(ShadowMetricsLogger.getLogs().contains(
                new ShadowMetricsLogger.Log(null,
                        MetricsProto.MetricsEvent.ACTION_PERMISSION_REQUEST_UNKNOWN,
                        "testPackage")));
    }

    @Test
    public void testInvalidRequestedUserBuild() throws Throwable {
        EventLogger.logPermissionRequested(null, "invalid", "testPackage");

        assertEquals(1, ShadowMetricsLogger.getLogs().size());
        assertTrue(ShadowMetricsLogger.getLogs().contains(
                new ShadowMetricsLogger.Log(null,
                        MetricsProto.MetricsEvent.ACTION_PERMISSION_REQUEST_UNKNOWN,
                        "testPackage")));
    }

    @Test
    public void testInvalidDeniedUserBuild() throws Throwable {
        EventLogger.logPermissionDenied(null, "invalid", "testPackage");

        assertEquals(1, ShadowMetricsLogger.getLogs().size());
        assertTrue(ShadowMetricsLogger.getLogs().contains(
                new ShadowMetricsLogger.Log(null,
                        MetricsProto.MetricsEvent.ACTION_PERMISSION_REQUEST_UNKNOWN + 2,
                        "testPackage")));
    }
}
+0 −86
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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.shadows;

import android.content.Context;

import com.android.internal.logging.MetricsLogger;

import libcore.util.Objects;

import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;

import java.util.ArrayList;

/**
 * MetricsLogger that just adds logs to a list
 */
@Implements(MetricsLogger.class)
public class ShadowMetricsLogger {
    /** Collected logs */
    private static ArrayList<Log> sLogs = new ArrayList<>();

    /**
     * Clear all previously collected logs
     */
    public static void clearLogs() {
        sLogs.clear();
    }

    /**
     * @return All logs collected since the last {@link #clearLogs()}.
     */
    public static ArrayList<Log> getLogs() {
        return sLogs;
    }

    @Implementation
    public static void action(Context context, int category, String pkg) {
        sLogs.add(new Log(context, category, pkg));
    }

    public static class Log {
        public final Context context;
        public final int category;
        public final String pkg;

        public Log(Context context, int category, String pkg) {
            this.context = context;
            this.category = category;
            this.pkg = pkg;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null || !(obj instanceof Log)) {
                return false;
            } else {
                Log otherLog = (Log) obj;

                return Objects.equal(otherLog.context, context) && otherLog.category == category
                        && Objects.equal(otherLog.pkg, pkg);
            }
        }

        @Override
        public int hashCode() {
            return ((context == null) ? 0 : context.hashCode()) + category + ((pkg == null) ? 0
                    : pkg.hashCode());
        }
    }
}
Loading