// Apps under strict background restrictions simply don't get to have foreground // services, so now that we've enforced the startForegroundService() contract // we only do the machinery of making the service foreground when the app // is not restricted. if (!ignoreForeground) { if (r.foregroundId != id) { cancelForegroundNotificationLocked(r); r.foregroundId = id; } notification.flags |= Notification.FLAG_FOREGROUND_SERVICE; r.foregroundNoti = notification; if (!r.isForeground) { finalServiceMapsmap= getServiceMapLocked(r.userId); if (smap != null) { ActiveForegroundAppactive= smap.mActiveForegroundApps.get(r.packageName); if (active == null) { active = newActiveForegroundApp(); active.mPackageName = r.packageName; active.mUid = r.appInfo.uid; active.mShownWhileScreenOn = mScreenOn; if (r.app != null) { active.mAppOnTop = active.mShownWhileTop = r.app.uidRecord.curProcState <= ActivityManager.PROCESS_STATE_TOP; } active.mStartTime = active.mStartVisibleTime = SystemClock.elapsedRealtime(); smap.mActiveForegroundApps.put(r.packageName, active); requestUpdateActiveForegroundAppsLocked(smap, 0); } active.mNumActive++; } r.isForeground = true; mAm.mAppOpsService.startOperation( AppOpsManager.getToken(mAm.mAppOpsService), AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, true); StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortName, StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER); } r.postNotification(); if (r.app != null) { updateServiceForegroundLocked(r.app, true); } getServiceMapLocked(r.userId).ensureNotStartingBackgroundLocked(r); mAm.notifyPackageUse(r.serviceInfo.packageName, PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE); }
ams.mHandler.post(newRunnable() { publicvoidrun() { NotificationManagerInternalnm= LocalServices.getService( NotificationManagerInternal.class); if (nm == null) { return; } NotificationlocalForegroundNoti= _foregroundNoti; try { if (localForegroundNoti.getSmallIcon() == null) { // It is not correct for the caller to not supply a notification // icon, but this used to be able to slip through, so for // those dirty apps we will create a notification clearly // blaming the app. Slog.v(TAG, "Attempted to start a foreground service (" + name + ") with a broken notification (no icon: " + localForegroundNoti + ")");
localForegroundNoti = notiBuilder.build(); } catch (PackageManager.NameNotFoundException e) { } } if (nm.getNotificationChannel(localPackageName, appUid, localForegroundNoti.getChannelId()) == null) { inttargetSdkVersion= Build.VERSION_CODES.O_MR1; try { finalApplicationInfoapplicationInfo= ams.mContext.getPackageManager().getApplicationInfoAsUser( appInfo.packageName, 0, userId); targetSdkVersion = applicationInfo.targetSdkVersion; } catch (PackageManager.NameNotFoundException e) { } if (targetSdkVersion >= Build.VERSION_CODES.O_MR1) { thrownewRuntimeException( "invalid channel for service notification: " + foregroundNoti); } } if (localForegroundNoti.getSmallIcon() == null) { // Notifications whose icon is 0 are defined to not show // a notification, silently ignoring it. We don't want to // just ignore it, we want to prevent the service from // being foreground. thrownewRuntimeException("invalid service notification: " + foregroundNoti); } nm.enqueueNotification(localPackageName, localPackageName, appUid, appPid, null, localForegroundId, localForegroundNoti,userId);
foregroundNoti = localForegroundNoti; // save it for amending next time } catch (RuntimeException e) { Slog.w(TAG, "Error showing notification for service", e); // If it gave us a garbage notification, it doesn't // get to be foreground. ams.setServiceForeground(name, ServiceRecord.this, 0, null, 0); ams.crashApplication(appUid, appPid, localPackageName, -1, "Bad notification for startForeground: " + e); } } });