Merge "Fix various FGS notification deferral issues" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-06-01 17:32:02 +00:00
committed by Android (Google) Code Review
8 changed files with 315 additions and 66 deletions

View File

@@ -48,6 +48,23 @@ import java.util.Set;
*/
public abstract class ActivityManagerInternal {
public enum ServiceNotificationPolicy {
/**
* The Notification is not associated with any foreground service.
*/
NOT_FOREGROUND_SERVICE,
/**
* The Notification is associated with a foreground service, but the
* notification system should handle it just like non-FGS notifications.
*/
SHOW_IMMEDIATELY,
/**
* The Notification is associated with a foreground service, and the
* notification system should ignore it unless it has already been shown (in
* which case it should be used to update the currently displayed UI).
*/
UPDATE_ONLY
}
// Access modes for handleIncomingUser.
public static final int ALLOW_NON_FULL = 0;
@@ -457,6 +474,24 @@ public abstract class ActivityManagerInternal {
public abstract boolean hasForegroundServiceNotification(String pkg, @UserIdInt int userId,
String channelId);
/**
* Tell the service lifecycle logic that the given Notification content is now
* canonical for any foreground-service visibility policy purposes.
*
* Returns a description of any FGs-related policy around the given Notification:
* not associated with an FGS; ensure display; or only update if already displayed.
*/
public abstract ServiceNotificationPolicy applyForegroundServiceNotification(
Notification notification, int id, String pkg, @UserIdInt int userId);
/**
* Callback from the notification subsystem that the given FGS notification has
* been shown or updated. This can happen after either Service.startForeground()
* or NotificationManager.notify().
*/
public abstract void onForegroundServiceNotificationUpdate(Notification notification,
int id, String pkg, @UserIdInt int userId);
/**
* If the given app has any FGSs whose notifications are in the given channel,
* stop them.

View File

@@ -79,8 +79,10 @@ import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UptimeMillisLong;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal.ServiceNotificationPolicy;
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -213,6 +215,9 @@ public final class ActiveServices {
// at the same time.
final int mMaxStartingBackground;
/**
* Master service bookkeeping, keyed by user number.
*/
final SparseArray<ServiceMap> mServiceMap = new SparseArray<>();
/**
@@ -1811,7 +1816,7 @@ public final class ActiveServices {
showFgsBgRestrictedNotificationLocked(r);
updateServiceForegroundLocked(psr, true);
ignoreForeground = true;
logForegroundServiceStateChanged(r,
logFGSStateChangeLocked(r,
FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED,
0);
if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID,
@@ -1859,6 +1864,7 @@ public final class ActiveServices {
active.mNumActive++;
}
r.isForeground = true;
r.mLogEntering = true;
enterForeground = true;
r.mStartForegroundCount++;
r.mFgsEnterTime = SystemClock.uptimeMillis();
@@ -1881,14 +1887,7 @@ public final class ActiveServices {
}
// Even if the service is already a FGS, we need to update the notification,
// so we need to call it again.
postFgsNotificationLocked(r);
if (enterForeground) {
// Because we want to log what's updated in postFgsNotificationLocked(),
// this must be called after postFgsNotificationLocked().
logForegroundServiceStateChanged(r,
FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER,
0);
}
r.postNotification();
if (r.app != null) {
updateServiceForegroundLocked(psr, true);
}
@@ -1937,7 +1936,7 @@ public final class ActiveServices {
AppOpsManager.getToken(mAm.mAppOpsService),
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null);
unregisterAppOpCallbackLocked(r);
logForegroundServiceStateChanged(r,
logFGSStateChangeLocked(r,
FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT,
r.mFgsExitTime > r.mFgsEnterTime
? (int)(r.mFgsExitTime - r.mFgsEnterTime) : 0);
@@ -1964,7 +1963,18 @@ public final class ActiveServices {
}
}
private boolean withinFgsDeferRateLimit(final int uid, final long now) {
private boolean withinFgsDeferRateLimit(ServiceRecord sr, final long now) {
// If we're still within the service's deferral period, then by definition
// deferral is not rate limited.
if (now < sr.fgDisplayTime) {
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, "FGS transition for " + sr
+ " within deferral period, no rate limit applied");
}
return false;
}
final int uid = sr.appInfo.uid;
final long eligible = mFgsDeferralEligible.get(uid, 0L);
if (DEBUG_FOREGROUND_SERVICE) {
if (now < eligible) {
@@ -1975,62 +1985,137 @@ public final class ActiveServices {
return now < eligible;
}
// TODO: remove as part of fixing b/173627642
ServiceNotificationPolicy applyForegroundServiceNotificationLocked(Notification notification,
final int id, final String pkg, final int userId) {
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, "Evaluating FGS policy for id=" + id
+ " pkg=" + pkg + " not=" + notification);
}
// Is there an FGS using this notification?
final ServiceMap smap = mServiceMap.get(userId);
if (smap == null) {
// No services in this user at all
return ServiceNotificationPolicy.NOT_FOREGROUND_SERVICE;
}
for (int i = 0; i < smap.mServicesByInstanceName.size(); i++) {
final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i);
if (id != sr.foregroundId || !pkg.equals(sr.appInfo.packageName)) {
// Not this one; keep looking
continue;
}
// Found; it is associated with an FGS. Make sure that it's flagged:
// it may have entered the bookkeeping outside of Service-related
// APIs. We also make sure to take this latest Notification as
// the content to be shown (immediately or eventually).
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, " FOUND: notification is for " + sr);
}
notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
sr.foregroundNoti = notification;
// ...and determine immediate vs deferred display policy for it
final boolean showNow = shouldShowFgsNotificationLocked(sr);
if (showNow) {
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, " Showing immediately due to policy");
}
sr.mFgsNotificationDeferred = false;
return ServiceNotificationPolicy.SHOW_IMMEDIATELY;
}
// Deferring - kick off the timer if necessary, and tell the caller
// that it's to be shown only if it's an update to already-
// visible content (e.g. if it's an FGS adopting a
// previously-posted Notification).
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, " Deferring / update-only");
}
startFgsDeferralTimerLocked(sr);
return ServiceNotificationPolicy.UPDATE_ONLY;
}
// None of the services in this user are FGSs
return ServiceNotificationPolicy.NOT_FOREGROUND_SERVICE;
}
// No legacy-app behavior skew intended but there's a runtime E-stop if a need
// arises, so note that
@SuppressWarnings("AndroidFrameworkCompatChange")
private void postFgsNotificationLocked(ServiceRecord r) {
final int uid = r.appInfo.uid;
private boolean shouldShowFgsNotificationLocked(ServiceRecord r) {
final long now = SystemClock.uptimeMillis();
final boolean isLegacyApp = (r.appInfo.targetSdkVersion < Build.VERSION_CODES.S);
// Is the behavior enabled at all?
boolean showNow = !mAm.mConstants.mFlagFgsNotificationDeferralEnabled;
if (!showNow) {
// Did the app have another FGS notification deferred recently?
showNow = withinFgsDeferRateLimit(uid, now);
if (!mAm.mConstants.mFlagFgsNotificationDeferralEnabled) {
return true;
}
if (!showNow) {
// Legacy apps' FGS notifications are not deferred unless the relevant
// Has this service's deferral timer expired?
if (r.mFgsNotificationDeferred && now >= r.fgDisplayTime) {
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG, "FGS reached end of deferral period: " + r);
}
return true;
}
// Did the app have another FGS notification deferred recently?
if (withinFgsDeferRateLimit(r, now)) {
return true;
}
if (mAm.mConstants.mFlagFgsNotificationDeferralApiGated) {
// Legacy apps' FGS notifications are also deferred unless the relevant
// DeviceConfig element has been set
showNow = isLegacyApp && mAm.mConstants.mFlagFgsNotificationDeferralApiGated;
final boolean isLegacyApp = (r.appInfo.targetSdkVersion < Build.VERSION_CODES.S);
if (isLegacyApp) {
return true;
}
}
if (!showNow) {
// has the app forced deferral?
if (!r.foregroundNoti.isForegroundDisplayForceDeferred()) {
// is the notification such that it should show right away?
showNow = r.foregroundNoti.shouldShowForegroundImmediately();
if (DEBUG_FOREGROUND_SERVICE && showNow) {
// did we already show it?
if (r.mFgsNotificationShown) {
return true;
}
// has the app forced deferral?
if (!r.foregroundNoti.isForegroundDisplayForceDeferred()) {
// is the notification such that it should show right away?
if (r.foregroundNoti.shouldShowForegroundImmediately()) {
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, "FGS " + r
+ " notification policy says show immediately");
}
// or is this an type of FGS that always shows immediately?
if (!showNow) {
if ((r.foregroundServiceType & FGS_IMMEDIATE_DISPLAY_MASK) != 0) {
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, "FGS " + r
+ " type gets immediate display");
}
showNow = true;
}
}
} else {
return true;
}
// or is this an type of FGS that always shows immediately?
if ((r.foregroundServiceType & FGS_IMMEDIATE_DISPLAY_MASK) != 0) {
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, "FGS " + r + " notification is app deferred");
Slog.d(TAG_SERVICE, "FGS " + r
+ " type gets immediate display");
}
return true;
}
}
if (showNow) {
// fall through to return false: no policy dictates immediate display
} else {
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, "FGS " + r + " non-deferred notification");
Slog.d(TAG_SERVICE, "FGS " + r + " notification is app deferred");
}
r.postNotification();
r.mFgsNotificationDeferred = false;
r.mFgsNotificationShown = true;
return;
// fall through to return false
}
r.mFgsNotificationDeferred = true;
r.mFgsNotificationShown = false;
return false;
}
// Target SDK consultation here is strictly for logging purposes, not
// behavioral variation.
@SuppressWarnings("AndroidFrameworkCompatChange")
private void startFgsDeferralTimerLocked(ServiceRecord r) {
final long now = SystemClock.uptimeMillis();
final int uid = r.appInfo.uid;
// schedule the actual notification post
long when = now + mAm.mConstants.mFgsNotificationDeferralInterval;
// If there are already deferred FGS notifications for this app,
@@ -2053,11 +2138,14 @@ public final class ActiveServices {
final long nextEligible = when + mAm.mConstants.mFgsNotificationDeferralExclusionTime;
mFgsDeferralEligible.put(uid, nextEligible);
r.fgDisplayTime = when;
r.mFgsNotificationDeferred = true;
r.mFgsNotificationShown = false;
mPendingFgsNotifications.add(r);
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, "FGS " + r
+ " notification in " + (when - now) + " ms");
}
final boolean isLegacyApp = (r.appInfo.targetSdkVersion < Build.VERSION_CODES.S);
if (isLegacyApp) {
Slog.i(TAG_SERVICE, "Deferring FGS notification in legacy app "
+ r.appInfo.packageName + "/" + UserHandle.formatUid(r.appInfo.uid)
@@ -2089,9 +2177,16 @@ public final class ActiveServices {
if (r.isForeground && r.app != null) {
r.postNotification();
r.mFgsNotificationShown = true;
} else if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, " - service no longer running/fg, ignoring");
} else {
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, " - service no longer running/fg, ignoring");
}
}
// Regardless of whether we needed to post the notification or the
// service is no longer running, we may not have logged its FGS
// transition yet depending on the timing and API sequence that led
// to this point - so make sure to do so.
maybeLogFGSStateEnteredLocked(r);
}
}
if (DEBUG_FOREGROUND_SERVICE) {
@@ -2102,6 +2197,60 @@ public final class ActiveServices {
}
};
private void maybeLogFGSStateEnteredLocked(ServiceRecord r) {
if (r.mLogEntering) {
logFGSStateChangeLocked(r,
FrameworkStatsLog
.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER,
0);
r.mLogEntering = false;
}
}
/**
* Callback from NotificationManagerService whenever it posts a notification
* associated with a foreground service. This is the unified handling point
* for the disjoint code flows that affect an FGS's notifiation content and
* visibility, starting with both Service.startForeground() and
* NotificationManager.notify().
*/
public void onForegroundServiceNotificationUpdateLocked(Notification notification,
final int id, final String pkg, @UserIdInt final int userId) {
// If this happens to be a Notification for an FGS still in its deferral period,
// drop the deferral and make sure our content bookkeeping is up to date.
for (int i = mPendingFgsNotifications.size() - 1; i >= 0; i--) {
final ServiceRecord sr = mPendingFgsNotifications.get(i);
if (userId == sr.userId
&& id == sr.foregroundId
&& sr.appInfo.packageName.equals(pkg)) {
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, "Notification shown; canceling deferral of "
+ sr);
}
maybeLogFGSStateEnteredLocked(sr);
sr.mFgsNotificationShown = true;
sr.mFgsNotificationDeferred = false;
mPendingFgsNotifications.remove(i);
}
}
// And make sure to retain the latest notification content for the FGS
ServiceMap smap = mServiceMap.get(userId);
if (smap != null) {
for (int i = 0; i < smap.mServicesByInstanceName.size(); i++) {
final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i);
if (sr.isForeground
&& id == sr.foregroundId
&& sr.appInfo.packageName.equals(pkg)) {
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, "Recording shown notification for "
+ sr);
}
sr.foregroundNoti = notification;
}
}
}
}
/** Registers an AppOpCallback for monitoring special AppOps for this foreground service. */
private void registerAppOpCallbackLocked(@NonNull ServiceRecord r) {
if (r.app == null) {
@@ -4016,7 +4165,7 @@ public final class ActiveServices {
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null);
unregisterAppOpCallbackLocked(r);
r.mFgsExitTime = SystemClock.uptimeMillis();
logForegroundServiceStateChanged(r,
logFGSStateChangeLocked(r,
FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT,
r.mFgsExitTime > r.mFgsEnterTime
? (int)(r.mFgsExitTime - r.mFgsEnterTime) : 0);
@@ -6022,7 +6171,7 @@ public final class ActiveServices {
* @param state one of ENTER/EXIT/DENIED event.
* @param durationMs Only meaningful for EXIT event, the duration from ENTER and EXIT state.
*/
private void logForegroundServiceStateChanged(ServiceRecord r, int state, int durationMs) {
private void logFGSStateChangeLocked(ServiceRecord r, int state, int durationMs) {
if (!ActivityManagerUtils.shouldSamplePackageForAtom(
r.packageName, mAm.mConstants.mFgsAtomSampleRate)) {
return;

View File

@@ -453,7 +453,7 @@ final class ActivityManagerConstants extends ContentObserver {
volatile long mFgsNotificationDeferralInterval = 10_000;
// Rate limit: minimum time after an app's FGS notification is deferred
// before another FGS notifiction from that app can be deferred.
// before another FGS notification from that app can be deferred.
volatile long mFgsNotificationDeferralExclusionTime = 2 * 60 * 1000L;
/**

View File

@@ -16058,6 +16058,24 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
@Override
public ServiceNotificationPolicy applyForegroundServiceNotification(
Notification notification, int id, String pkg, int userId) {
synchronized (ActivityManagerService.this) {
return mServices.applyForegroundServiceNotificationLocked(notification,
id, pkg, userId);
}
}
@Override
public void onForegroundServiceNotificationUpdate(Notification notification,
int id, String pkg, @UserIdInt int userId) {
synchronized (ActivityManagerService.this) {
mServices.onForegroundServiceNotificationUpdateLocked(notification,
id, pkg, userId);
}
}
@Override
public void stopForegroundServicesForChannel(String pkg, int userId,
String channelId) {

View File

@@ -109,6 +109,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
boolean fgWaiting; // is a timeout for going foreground already scheduled?
boolean isNotAppComponentUsage; // is service binding not considered component/package usage?
boolean isForeground; // is service currently in foreground mode?
boolean mLogEntering; // need to report fgs transition once deferral policy is known
int foregroundId; // Notification ID of last foreground req.
Notification foregroundNoti; // Notification record of foreground state.
long fgDisplayTime; // time at which the FGS notification should become visible

View File

@@ -30,6 +30,9 @@ public interface NotificationManagerInternal {
void cancelNotification(String pkg, String basePkg, int callingUid, int callingPid,
String tag, int id, int userId);
/** is the given notification currently showing? */
boolean isNotificationShown(String pkg, String tag, int notificationId, int userId);
void removeForegroundServiceFlagFromNotification(String pkg, int notificationId, int userId);
void onConversationRemoved(String pkg, int uid, Set<String> shortcuts);

View File

@@ -130,6 +130,7 @@ import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal.ServiceNotificationPolicy;
import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -3078,6 +3079,20 @@ public class NotificationManagerService extends SystemService {
}
}
protected void maybeReportForegroundServiceUpdate(final NotificationRecord r) {
if (r.isForegroundService()) {
// snapshot live state for the asynchronous operation
final StatusBarNotification sbn = r.getSbn();
final Notification notification = sbn.getNotification();
final int id = sbn.getId();
final String pkg = sbn.getPackageName();
final int userId = sbn.getUser().getIdentifier();
mHandler.post(() -> {
mAmi.onForegroundServiceNotificationUpdate(notification, id, pkg, userId);
});
}
}
private String getHistoryTitle(Notification n) {
CharSequence title = null;
if (n.extras != null) {
@@ -5070,7 +5085,7 @@ public class NotificationManagerService extends SystemService {
}
@Override
public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {
enforceSystemOrSystemUIOrSamePackage(pkg,
"request policy access status for another package");
return checkPolicyAccess(pkg);
@@ -5725,9 +5740,7 @@ public class NotificationManagerService extends SystemService {
summaryNotification.extras.putAll(extras);
Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
if (appIntent != null) {
final ActivityManagerInternal ami = LocalServices
.getService(ActivityManagerInternal.class);
summaryNotification.contentIntent = ami.getPendingIntentActivityAsApp(
summaryNotification.contentIntent = mAmi.getPendingIntentActivityAsApp(
0, appIntent, PendingIntent.FLAG_IMMUTABLE, null,
pkg, appInfo.uid);
}
@@ -5778,7 +5791,7 @@ public class NotificationManagerService extends SystemService {
return "callState";
}
return null;
};
}
private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) {
JSONObject dump = new JSONObject();
@@ -6058,6 +6071,11 @@ public class NotificationManagerService extends SystemService {
cancelNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, userId);
}
@Override
public boolean isNotificationShown(String pkg, String tag, int notificationId, int userId) {
return isNotificationShownInternal(pkg, tag, notificationId, userId);
}
@Override
public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
int userId) {
@@ -6141,16 +6159,22 @@ public class NotificationManagerService extends SystemService {
mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
}
boolean isNotificationShownInternal(String pkg, String tag, int notificationId, int userId) {
synchronized (mNotificationLock) {
return findNotificationLocked(pkg, tag, notificationId, userId) != null;
}
}
void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
int incomingUserId) {
enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
incomingUserId, false);
incomingUserId, false);
}
void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
int incomingUserId, boolean postSilently) {
final int callingPid, final String tag, final int id, final Notification notification,
int incomingUserId, boolean postSilently) {
if (DBG) {
Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
+ " notification=" + notification);
@@ -6185,6 +6209,22 @@ public class NotificationManagerService extends SystemService {
return;
}
// Notifications passed to setForegroundService() have FLAG_FOREGROUND_SERVICE,
// but it's also possible that the app has called notify() with an update to an
// FGS notification that hasn't yet been displayed. Make sure we check for any
// FGS-related situation up front, outside of any locks so it's safe to call into
// the Activity Manager.
final ServiceNotificationPolicy policy = mAmi.applyForegroundServiceNotification(
notification, id, pkg, userId);
if (policy == ServiceNotificationPolicy.UPDATE_ONLY) {
// Proceed if the notification is already showing/known, otherwise ignore
// because the service lifecycle logic has retained responsibility for its
// handling.
if (!isNotificationShownInternal(pkg, tag, id, userId)) {
return;
}
}
mUsageStats.registerEnqueuedByApp(pkg);
final StatusBarNotification n = new StatusBarNotification(
@@ -6287,19 +6327,17 @@ public class NotificationManagerService extends SystemService {
if (notification.allPendingIntents != null) {
final int intentCount = notification.allPendingIntents.size();
if (intentCount > 0) {
final ActivityManagerInternal am = LocalServices
.getService(ActivityManagerInternal.class);
final long duration = LocalServices.getService(
DeviceIdleInternal.class).getNotificationAllowlistDuration();
for (int i = 0; i < intentCount; i++) {
PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
if (pendingIntent != null) {
am.setPendingIntentAllowlistDuration(pendingIntent.getTarget(),
mAmi.setPendingIntentAllowlistDuration(pendingIntent.getTarget(),
ALLOWLIST_TOKEN, duration,
TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
REASON_NOTIFICATION_SERVICE,
"NotificationManagerService");
am.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(),
mAmi.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(),
ALLOWLIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER
| FLAG_SERVICE_SENDER));
}
@@ -7108,6 +7146,7 @@ public class NotificationManagerService extends SystemService {
maybeRecordInterruptionLocked(r);
maybeRegisterMessageSent(r);
maybeReportForegroundServiceUpdate(r);
// Log event to statsd
mNotificationRecordLogger.maybeLogNotificationPosted(r, old, position,

View File

@@ -877,6 +877,10 @@ public final class NotificationRecord {
return mHidden;
}
public boolean isForegroundService() {
return 0 != (getFlags() & Notification.FLAG_FOREGROUND_SERVICE);
}
/**
* Override of all alerting information on the channel and notification. Used when notifications
* are reposted in response to direct user action and thus don't need to alert.