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

Commit 4fb8913b authored by Yu-Ting Tseng's avatar Yu-Ting Tseng
Browse files

Log BAL and full screen intent to statsd.

Test: atest StatusBarNotificationActivityStarterTest
Test: atest ActivityStarterTests
Bug: 261910877
Change-Id: I4fdfbe80ea0c368a4809e5613e5f9c3a8369e2a3
parent 2a85f93f
Loading
Loading
Loading
Loading
+21 −4
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
@@ -45,6 +46,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.EventLogTags;
@@ -74,12 +76,14 @@ import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.wmshell.BubblesManager;

import dagger.Lazy;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.Executor;

import javax.inject.Inject;

import dagger.Lazy;

/**
 * Status bar implementation of {@link NotificationActivityStarter}.
@@ -572,16 +576,29 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
        });

        // not immersive & a fullscreen alert should be shown
        final PendingIntent fullscreenIntent =
        final PendingIntent fullScreenIntent =
                entry.getSbn().getNotification().fullScreenIntent;
        mLogger.logSendingFullScreenIntent(entry, fullscreenIntent);
        mLogger.logSendingFullScreenIntent(entry, fullScreenIntent);
        try {
            EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
                    entry.getKey());
            mCentralSurfaces.wakeUpForFullScreenIntent();
            fullscreenIntent.send();
            fullScreenIntent.send();
            entry.notifyFullScreenIntentLaunched();
            mMetricsLogger.count("note_fullscreen", 1);

            String activityName;
            List<ResolveInfo> resolveInfos = fullScreenIntent.queryIntentComponents(0);
            if (resolveInfos.size() > 0 && resolveInfos.get(0) != null
                    && resolveInfos.get(0).activityInfo != null
                    && resolveInfos.get(0).activityInfo.name != null) {
                activityName = resolveInfos.get(0).activityInfo.name;
            } else {
                activityName = "";
            }
            FrameworkStatsLog.write(FrameworkStatsLog.FULL_SCREEN_INTENT_LAUNCHED,
                    fullScreenIntent.getCreatorUid(),
                    activityName);
        } catch (PendingIntent.CanceledException e) {
            // ignore
        }
+45 −1
Original line number Diff line number Diff line
@@ -18,6 +18,9 @@ package com.android.systemui.statusbar.phone;

import static android.service.notification.NotificationListenerService.REASON_CLICK;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;

import static org.mockito.AdditionalAnswers.answerVoid;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -28,7 +31,6 @@ import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
@@ -38,6 +40,8 @@ import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -51,6 +55,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.SysuiTestCase;
@@ -90,9 +95,12 @@ import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

@@ -398,4 +406,40 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
        // THEN display should try wake up for the full screen intent
        verify(mCentralSurfaces).wakeUpForFullScreenIntent();
    }

    @Test
    public void testOnFullScreenIntentWhenDozing_logToStatsd() {
        final int kTestUid = 12345;
        final String kTestActivityName = "TestActivity";
        // GIVEN entry that can has a full screen intent that can show
        PendingIntent mockFullScreenIntent = mock(PendingIntent.class);
        when(mockFullScreenIntent.getCreatorUid()).thenReturn(kTestUid);
        ResolveInfo resolveInfo = new ResolveInfo();
        resolveInfo.activityInfo = new ActivityInfo();
        resolveInfo.activityInfo.name = kTestActivityName;
        when(mockFullScreenIntent.queryIntentComponents(anyInt()))
                .thenReturn(Arrays.asList(resolveInfo));
        Notification.Builder nb = new Notification.Builder(mContext, "a")
                .setContentTitle("foo")
                .setSmallIcon(android.R.drawable.sym_def_app_icon)
                .setFullScreenIntent(mockFullScreenIntent, true);
        StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0,
                "tag" + System.currentTimeMillis(), 0, 0,
                nb.build(), new UserHandle(0), null, 0);
        NotificationEntry entry = mock(NotificationEntry.class);
        when(entry.getImportance()).thenReturn(NotificationManager.IMPORTANCE_HIGH);
        when(entry.getSbn()).thenReturn(sbn);
        MockitoSession mockingSession = mockitoSession()
                .mockStatic(FrameworkStatsLog.class)
                .strictness(Strictness.LENIENT)
                .startMocking();

        // WHEN
        mNotificationActivityStarter.launchFullScreenIntent(entry);

        // THEN the full screen intent should be logged to statsd.
        verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.FULL_SCREEN_INTENT_LAUNCHED,
                kTestUid, kTestActivityName));
        mockingSession.finishMocking();
    }
}
+74 −48
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.Slog;

import com.android.internal.util.FrameworkStatsLog;
import com.android.server.am.PendingIntentRecord;

import java.lang.annotation.Retention;
@@ -176,22 +177,24 @@ public class BackgroundActivityStartController {
            if (callingUid == Process.ROOT_UID
                    || callingAppId == Process.SYSTEM_UID
                    || callingAppId == Process.NFC_UID) {
                return logStartAllowedAndReturnCode(/*background*/ false, callingUid,
                        BAL_ALLOW_ALLOWLISTED_UID, "Important callingUid");
                return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_UID, /*background*/ false,
                        callingUid, realCallingUid, intent, "Important callingUid");
            }

            // Always allow home application to start activities.
            if (isHomeApp(callingUid, callingPackage)) {
                return logStartAllowedAndReturnCode(/*background*/ false, callingUid,
                        BAL_ALLOW_ALLOWLISTED_COMPONENT, "Home app");
                return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
                        /*background*/ false, callingUid, realCallingUid, intent,
                        "Home app");
            }

            // IME should always be allowed to start activity, like IME settings.
            final WindowState imeWindow =
                    mService.mRootWindowContainer.getCurrentInputMethodWindow();
            if (imeWindow != null && callingAppId == imeWindow.mOwnerUid) {
                return logStartAllowedAndReturnCode(/*background*/ false, callingUid,
                        BAL_ALLOW_ALLOWLISTED_COMPONENT, "Active ime");
                return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
                        /*background*/ false, callingUid, realCallingUid, intent,
                        "Active ime");
            }
        }

@@ -218,8 +221,8 @@ public class BackgroundActivityStartController {
                                && callingUidHasAnyVisibleWindow)
                        || isCallingUidPersistentSystemProcess;
        if (useCallingUidState && allowCallingUidStartActivity) {
            return logStartAllowedAndReturnCode(/*background*/ false,
                    BAL_ALLOW_VISIBLE_WINDOW,
            return logStartAllowedAndReturnCode(BAL_ALLOW_VISIBLE_WINDOW,
                    /*background*/ false, callingUid, realCallingUid, intent,
                    "callingUidHasAnyVisibleWindow = "
                            + callingUid
                            + ", isCallingUidPersistentSystemProcess = "
@@ -254,8 +257,8 @@ public class BackgroundActivityStartController {
                    Process.getAppUidForSdkSandboxUid(UserHandle.getAppId(realCallingUid));

            if (mService.hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) {
                return logStartAllowedAndReturnCode(/*background*/ false, realCallingUid,
                        BAL_ALLOW_SDK_SANDBOX,
                return logStartAllowedAndReturnCode(BAL_ALLOW_SDK_SANDBOX,
                        /*background*/ false, callingUid, realCallingUid, intent,
                        "uid in SDK sandbox has visible (non-toast) window");
            }
        }
@@ -276,16 +279,16 @@ public class BackgroundActivityStartController {
                                    -1,
                                    true)
                            == PackageManager.PERMISSION_GRANTED) {
                return logStartAllowedAndReturnCode(/*background*/ false, callingUid,
                        BAL_ALLOW_PENDING_INTENT,
                return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
                        /*background*/ false, callingUid, realCallingUid, intent,
                        "realCallingUid has BAL permission. realCallingUid: " + realCallingUid);
            }

            // don't abort if the realCallingUid has a visible window
            // TODO(b/171459802): We should check appSwitchAllowed also
            if (realCallingUidHasAnyVisibleWindow) {
                return logStartAllowedAndReturnCode(/*background*/ false,
                        callingUid, BAL_ALLOW_PENDING_INTENT,
                return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
                        /*background*/ false, callingUid, realCallingUid, intent,
                        "realCallingUid has visible (non-toast) window. realCallingUid: "
                                + realCallingUid);
            }
@@ -293,9 +296,8 @@ public class BackgroundActivityStartController {
            // wasn't allowed to start an activity
            if (isRealCallingUidPersistentSystemProcess
                    && backgroundStartPrivileges.allowsBackgroundActivityStarts()) {
                return logStartAllowedAndReturnCode(/*background*/ false,
                        callingUid,
                        BAL_ALLOW_PENDING_INTENT,
                return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
                        /*background*/ false, callingUid, realCallingUid, intent,
                        "realCallingUid is persistent system process AND intent "
                                + "sender allowed (allowBackgroundActivityStart = true). "
                                + "realCallingUid: " + realCallingUid);
@@ -303,8 +305,9 @@ public class BackgroundActivityStartController {
            // don't abort if the realCallingUid is an associated companion app
            if (mService.isAssociatedCompanionApp(
                    UserHandle.getUserId(realCallingUid), realCallingUid)) {
                return logStartAllowedAndReturnCode(/*background*/ false, callingUid,
                        BAL_ALLOW_PENDING_INTENT,  "realCallingUid is a companion app. "
                return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
                        /*background*/ false, callingUid, realCallingUid, intent,
                        "realCallingUid is a companion app. "
                                + "realCallingUid: " + realCallingUid);
            }
        }
@@ -312,25 +315,28 @@ public class BackgroundActivityStartController {
            // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
            if (ActivityTaskManagerService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND,
                    callingPid, callingUid) == PERMISSION_GRANTED) {
                return logStartAllowedAndReturnCode(/*background*/ true, callingUid,
                    BAL_ALLOW_PERMISSION,
                return logStartAllowedAndReturnCode(BAL_ALLOW_PERMISSION,
                        /*background*/ true, callingUid, realCallingUid, intent,
                        "START_ACTIVITIES_FROM_BACKGROUND permission granted");
            }
            // don't abort if the caller has the same uid as the recents component
            if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
                return logStartAllowedAndReturnCode(/*background*/ true, callingUid,
                        BAL_ALLOW_ALLOWLISTED_COMPONENT, "Recents Component");
                return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
                        /*background*/ true, callingUid, realCallingUid,
                        intent, "Recents Component");
            }
            // don't abort if the callingUid is the device owner
            if (mService.isDeviceOwner(callingUid)) {
                return logStartAllowedAndReturnCode(/*background*/ true, callingUid,
                        BAL_ALLOW_ALLOWLISTED_COMPONENT, "Device Owner");
                return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
                        /*background*/ true, callingUid, realCallingUid,
                        intent, "Device Owner");
            }
            // don't abort if the callingUid has companion device
            final int callingUserId = UserHandle.getUserId(callingUid);
            if (mService.isAssociatedCompanionApp(callingUserId, callingUid)) {
                return logStartAllowedAndReturnCode(/*background*/ true, callingUid,
                        BAL_ALLOW_ALLOWLISTED_COMPONENT, "Companion App");
                return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
                        /*background*/ true, callingUid, realCallingUid,
                        intent, "Companion App");
            }
            // don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission
            if (mService.hasSystemAlertWindowPermission(callingUid, callingPid, callingPackage)) {
@@ -339,8 +345,9 @@ public class BackgroundActivityStartController {
                        "Background activity start for "
                                + callingPackage
                                + " allowed because SYSTEM_ALERT_WINDOW permission is granted.");
                return logStartAllowedAndReturnCode(/*background*/ true, callingUid,
                        BAL_ALLOW_SAW_PERMISSION, "SYSTEM_ALERT_WINDOW permission is granted");
                return logStartAllowedAndReturnCode(BAL_ALLOW_SAW_PERMISSION,
                        /*background*/ true, callingUid, realCallingUid,
                        intent, "SYSTEM_ALERT_WINDOW permission is granted");
            }
            // don't abort if the callingUid and callingPackage have the
            // OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop
@@ -349,8 +356,8 @@ public class BackgroundActivityStartController {
                    callingUid,
                    callingPackage)
                    == AppOpsManager.MODE_ALLOWED) {
                return logStartAllowedAndReturnCode(/*background*/ true, callingUid,
                    BAL_ALLOW_PERMISSION,
                return logStartAllowedAndReturnCode(BAL_ALLOW_PERMISSION,
                        /*background*/ true, callingUid, realCallingUid, intent,
                        "OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop is granted");
            }
        }
@@ -369,7 +376,8 @@ public class BackgroundActivityStartController {
            @BalCode int balAllowedForCaller = callerApp
                    .areBackgroundActivityStartsAllowed(appSwitchState);
            if (balAllowedForCaller != BAL_BLOCK) {
                return logStartAllowedAndReturnCode(/*background*/ true, balAllowedForCaller,
                return logStartAllowedAndReturnCode(balAllowedForCaller,
                        /*background*/ true, callingUid, realCallingUid, intent,
                        "callerApp process (pid = " + callerApp.getPid()
                                + ", uid = " + callerAppUid + ") is allowed");
            }
@@ -382,7 +390,8 @@ public class BackgroundActivityStartController {
                    int balAllowedForUid = proc.areBackgroundActivityStartsAllowed(appSwitchState);
                    if (proc != callerApp
                            && balAllowedForUid != BAL_BLOCK) {
                        return logStartAllowedAndReturnCode(/*background*/ true, balAllowedForUid,
                        return logStartAllowedAndReturnCode(balAllowedForUid,
                                /*background*/ true, callingUid, realCallingUid, intent,
                                "process" + proc.getPid()
                                        + " from uid " + callerAppUid + " is allowed");
                    }
@@ -448,27 +457,21 @@ public class BackgroundActivityStartController {
        return BAL_BLOCK;
    }

    private int logStartAllowedAndReturnCode(boolean background, int callingUid, int code,
            String msg) {
        if (DEBUG_ACTIVITY_STARTS) {
            return logStartAllowedAndReturnCode(background, code,
                    msg, "callingUid: " + callingUid);
        }
        return code;
    static @BalCode int logStartAllowedAndReturnCode(@BalCode int code, boolean background,
            int callingUid, int realCallingUid, Intent intent, int pid, String msg) {
        return logStartAllowedAndReturnCode(code, background, callingUid, realCallingUid, intent,
                DEBUG_ACTIVITY_STARTS ?  ("[Process(" + pid + ")]" + msg) : "");
    }

    private int logStartAllowedAndReturnCode(boolean background, int code,
            String... msg) {
    static @BalCode int logStartAllowedAndReturnCode(@BalCode int code, boolean background,
            int callingUid, int realCallingUid, Intent intent, String msg) {
        statsLogBalAllowed(code, callingUid, realCallingUid, intent);
        if (DEBUG_ACTIVITY_STARTS) {
            StringBuilder builder = new StringBuilder();
            if (background) {
                builder.append("Background ");
            }
            builder.append("Activity start allowed: ");
            for (int i = 0; i < msg.length; i++) {
                builder.append(msg[i]);
                builder.append(". ");
            }
            builder.append("Activity start allowed: " + msg + ". callingUid: " + callingUid + ". ");
            builder.append("BAL Code: ");
            builder.append(code);
            Slog.d(TAG,  builder.toString());
@@ -482,4 +485,27 @@ public class BackgroundActivityStartController {
                /* name= */ "system_exempt_from_activity_bg_start_restriction_enabled",
                /* defaultValue= */ true);
    }

    private static void statsLogBalAllowed(
            @BalCode int code, int callingUid, int realCallingUid, Intent intent) {
        if (code == BAL_ALLOW_PENDING_INTENT
                && (callingUid == Process.SYSTEM_UID || realCallingUid == Process.SYSTEM_UID)) {
            String activityName =
                    intent != null ? intent.getComponent().flattenToShortString() : "";
            FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED,
                    activityName,
                    code,
                    callingUid,
                    realCallingUid);
        }
        if (code == BAL_ALLOW_PERMISSION || code == BAL_ALLOW_FOREGROUND
                    || code == BAL_ALLOW_SAW_PERMISSION) {
            // We don't need to know which activity in this case.
            FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED,
                    /*activityName*/ "",
                    code,
                    callingUid,
                    realCallingUid);
        }
    }
}
+16 −26
Original line number Diff line number Diff line
@@ -104,37 +104,29 @@ class BackgroundLaunchProcessController {
            long lastActivityFinishTime) {
        // Allow if the proc is instrumenting with background activity starts privs.
        if (hasBackgroundActivityStartPrivileges) {
            if (DEBUG_ACTIVITY_STARTS) {
                Slog.d(TAG, "[Process(" + pid
                        + ")] Activity start allowed: process instrumenting with background "
            return BackgroundActivityStartController.logStartAllowedAndReturnCode(
                    BAL_ALLOW_PERMISSION, /*background*/ true, uid, uid, /*intent*/ null,
                    pid, "Activity start allowed: process instrumenting with background "
                        + "activity starts privileges");
        }
            return BAL_ALLOW_PERMISSION;
        }
        // Allow if the flag was explicitly set.
        if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) {
            if (DEBUG_ACTIVITY_STARTS) {
                Slog.d(TAG, "[Process(" + pid
                        + ")] Activity start allowed: process allowed by token");
            }
            return BAL_ALLOW_PERMISSION;
            return BackgroundActivityStartController.logStartAllowedAndReturnCode(
                    BAL_ALLOW_PERMISSION, /*background*/ true, uid, uid, /*intent*/ null,
                    pid, "Activity start allowed: process allowed by token");
        }
        // Allow if the caller is bound by a UID that's currently foreground.
        if (isBoundByForegroundUid()) {
            if (DEBUG_ACTIVITY_STARTS) {
                Slog.d(TAG, "[Process(" + pid
                        + ")] Activity start allowed: process bound by foreground uid");
            }
            return BAL_ALLOW_VISIBLE_WINDOW;
            return BackgroundActivityStartController.logStartAllowedAndReturnCode(
                    BAL_ALLOW_VISIBLE_WINDOW, /*background*/ false, uid, uid, /*intent*/ null,
                    pid, "Activity start allowed: process bound by foreground uid");
        }
        // Allow if the caller has an activity in any foreground task.
        if (hasActivityInVisibleTask
                && (appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY)) {
            if (DEBUG_ACTIVITY_STARTS) {
                Slog.d(TAG, "[Process(" + pid
                        + ")] Activity start allowed: process has activity in foreground task");
            }
            return BAL_ALLOW_FOREGROUND;
            return BackgroundActivityStartController.logStartAllowedAndReturnCode(
                    BAL_ALLOW_FOREGROUND, /*background*/ false, uid, uid, /*intent*/ null,
                    pid, "Activity start allowed: process has activity in foreground task");
        }

        // If app switching is not allowed, we ignore all the start activity grace period
@@ -149,13 +141,11 @@ class BackgroundLaunchProcessController {
                // let app to be able to start background activity even it's in grace period.
                if (lastActivityLaunchTime > lastStopAppSwitchesTime
                        || lastActivityFinishTime > lastStopAppSwitchesTime) {
                    if (DEBUG_ACTIVITY_STARTS) {
                        Slog.d(TAG, "[Process(" + pid
                                + ")] Activity start allowed: within "
                    return BackgroundActivityStartController.logStartAllowedAndReturnCode(
                            BAL_ALLOW_GRACE_PERIOD, /*background*/ true, uid, uid, /*intent*/ null,
                            pid, "Activity start allowed: within "
                                    + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period");
                }
                    return BAL_ALLOW_GRACE_PERIOD;
                }
                if (DEBUG_ACTIVITY_STARTS) {
                    Slog.d(TAG, "[Process(" + pid + ")] Activity start within "
                            + ACTIVITY_BG_START_GRACE_PERIOD_MS
+66 −0

File changed.

Preview size limit exceeded, changes collapsed.