概述
1.NotificationManagerService(NMS)启动流程
SystemServer.java
/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
new SystemServer().run();
}
public SystemServer() {
// Check for factory test mode.
mFactoryTestMode = FactoryTest.getMode();
// Record process start information.
// Note SYSPROP_START_COUNT will increment by *2* on a FDE device when it fully boots;
// one for the password screen, second for the actual boot.
mStartCount = SystemProperties.getInt(SYSPROP_START_COUNT, 0) + 1;
mRuntimeStartElapsedTime = SystemClock.elapsedRealtime();
mRuntimeStartUptime = SystemClock.uptimeMillis();
Process.setStartTimes(mRuntimeStartElapsedTime, mRuntimeStartUptime);
// Remember if it's runtime restart(when sys.boot_completed is already set) or reboot
// We don't use "mStartCount > 1" here because it'll be wrong on a FDE device.
// TODO: mRuntimeRestart will *not* be set to true if the proccess crashes before
// sys.boot_completed is set. Fix it.
mRuntimeRestart = "1".equals(SystemProperties.get("sys.boot_completed"));
}
SystemServer 是Java世界的第一个进程。由init 进程fork 产生。用来启动fw中的服务。
private void run() {
// Start services.
try {
t.traceBegin("StartServices");
startBootstrapServices(t);
startCoreServices(t);
startOtherServices(t);
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
t.traceEnd(); // StartServices
}
}
/**
* Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
*/
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
t.traceBegin("StartNotificationManager");
mSystemServiceManager.startService(NotificationManagerService.class);
SystemNotificationChannels.removeDeprecated(context);
SystemNotificationChannels.createAll(context);
notification = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
t.traceEnd();
t.traceBegin("StartSystemUI");
try {
startSystemUi(context, windowManagerF);
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
t.traceEnd();
}
SystemServer启动的服务有很多,主要关注NMS和SystemUI。
/**
* Creates and starts a system service. The class must be a subclass of
* {@link com.android.server.SystemService}.
*
* @param serviceClass A Java class that implements the SystemService interface.
* @return The service instance, never null.
* @throws RuntimeException if the service fails to start.
*/
public <T extends SystemService> T startService(Class<T> serviceClass) {
try {
final String name = serviceClass.getName();
Slog.i(TAG, "Starting " + name);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);
// Create the service.
if (!SystemService.class.isAssignableFrom(serviceClass)) {
throw new RuntimeException("Failed to create " + name
+ ": service must extend " + SystemService.class.getName());
}
final T service;
try {
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
} catch (InstantiationException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service could not be instantiated", ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service must have a public constructor with a Context argument", ex);
} catch (NoSuchMethodException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service must have a public constructor with a Context argument", ex);
} catch (InvocationTargetException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service constructor threw an exception", ex);
}
startService(service);
return service;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
public void startService(@NonNull final SystemService service) {
// Register it.
mServices.add(service);
// Start it.
long time = SystemClock.elapsedRealtime();
try {
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + service.getClass().getName()
+ ": onStart threw an exception", ex);
}
warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
}
通过反射创建NMS 并调用 service.onStart();
NotificationManagerService.java
public NotificationManagerService(Context context) {
this(context,
new NotificationRecordLoggerImpl(),
new InstanceIdSequence(NOTIFICATION_INSTANCE_ID_MAX));
}
@VisibleForTesting
public NotificationManagerService(Context context,
NotificationRecordLogger notificationRecordLogger,
InstanceIdSequence notificationInstanceIdSequence) {
super(context);
mNotificationRecordLogger = notificationRecordLogger;
mNotificationInstanceIdSequence = notificationInstanceIdSequence;
Notification.processWhitelistToken = WHITELIST_TOKEN;
}
@Override
public void onStart() {
SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), (userId, r, muteOnReturn) -> {
try {
if (DBG) {
Slog.d(TAG, "Reposting " + r.getKey());
}
enqueueNotificationInternal(r.getSbn().getPackageName(), r.getSbn().getOpPkg(),
r.getSbn().getUid(), r.getSbn().getInitialPid(), r.getSbn().getTag(),
r.getSbn().getId(),
r.getSbn().getNotification(), userId, true);
} catch (Exception e) {
Slog.e(TAG, "Cannot un-snooze notification", e);
}
}, mUserProfiles);
final File systemDir = new File(Environment.getDataDirectory(), "system");
mRankingThread.start();
WorkerHandler handler = new WorkerHandler(Looper.myLooper());
init(handler, new RankingHandlerWorker(mRankingThread.getLooper()),
AppGlobals.getPackageManager(), getContext().getPackageManager(),
getLocalService(LightsManager.class),
new NotificationListeners(AppGlobals.getPackageManager()),
new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles,
AppGlobals.getPackageManager()),
new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
null, snoozeHelper, new NotificationUsageStats(getContext()),
new AtomicFile(new File(
systemDir, "notification_policy.xml"), "notification-policy"),
(ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
getGroupHelper(), ActivityManager.getService(),
LocalServices.getService(ActivityTaskManagerInternal.class),
LocalServices.getService(UsageStatsManagerInternal.class),
LocalServices.getService(DevicePolicyManagerInternal.class),
UriGrantsManager.getService(),
LocalServices.getService(UriGrantsManagerInternal.class),
(AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE),
getContext().getSystemService(UserManager.class),
new NotificationHistoryManager(getContext(), handler),
mStatsManager = (StatsManager) getContext().getSystemService(
Context.STATS_MANAGER),
getContext().getSystemService(TelephonyManager.class));
// register for various Intents
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
filter.addAction(Intent.ACTION_USER_PRESENT);
filter.addAction(Intent.ACTION_USER_STOPPED);
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_UNLOCKED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
IntentFilter pkgFilter = new IntentFilter();
pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
pkgFilter.addDataScheme("package");
getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
null);
IntentFilter suspendedPkgFilter = new IntentFilter();
suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
suspendedPkgFilter.addAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
suspendedPkgFilter, null, null);
IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
null);
IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
publishLocalService(NotificationManagerInternal.class, mInternalService);
}
NMS 的onStart()方法中初始化WorkerHandler此handler 运行在System_server 进程。注册一些广播监听如亮灭屏应用包变化 等。
private NotificationListeners mListeners;
// TODO: All tests should use this init instead of the one-off setters above.
@VisibleForTesting
void init(WorkerHandler handler, RankingHandler rankingHandler,
IPackageManager packageManager, PackageManager packageManagerClient,
LightsManager lightsManager, NotificationListeners notificationListeners,
NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
NotificationUsageStats usageStats, AtomicFile policyFile,
ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
ActivityTaskManagerInternal atm, UsageStatsManagerInternal appUsageStats,
DevicePolicyManagerInternal dpm, IUriGrantsManager ugm,
UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager,
NotificationHistoryManager historyManager, StatsManager statsManager,
TelephonyManager telephonyManager) {
mHandler = handler;
Resources resources = getContext().getResources();
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
mAccessibilityManager =
(AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
mAm = am;
mAtm = atm;
mUgm = ugm;
mUgmInternal = ugmInternal;
mPackageManager = packageManager;
mPackageManagerClient = packageManagerClient;
mAppOps = appOps;
mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
mAppUsageStats = appUsageStats;
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
mCompanionManager = companionManager;
mActivityManager = activityManager;
mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
mDpm = dpm;
mUm = userManager;
mPlatformCompat = IPlatformCompat.Stub.asInterface(
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
mUiHandler = new Handler(UiThread.get().getLooper());
String[] extractorNames;
try {
extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
} catch (Resources.NotFoundException e) {
extractorNames = new String[0];
}
mUsageStats = usageStats;
mMetricsLogger = new MetricsLogger();
mRankingHandler = rankingHandler;
mConditionProviders = conditionProviders;
mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders,
new SysUiStatsEvent.BuilderFactory());
mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
@Override
public void onConfigChanged() {
handleSavePolicyFile();
}
@Override
void onZenModeChanged() {
Binder.withCleanCallingIdentity(() -> {
sendRegisteredOnlyBroadcast(ACTION_INTERRUPTION_FILTER_CHANGED);
getContext().sendBroadcastAsUser(
new Intent(ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
UserHandle.ALL, permission.MANAGE_NOTIFICATIONS);
synchronized (mNotificationLock) {
updateInterruptionFilterLocked();
}
mRankingHandler.requestSort();
});
}
@Override
void onPolicyChanged() {
Binder.withCleanCallingIdentity(() -> {
sendRegisteredOnlyBroadcast(
NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
mRankingHandler.requestSort();
});
}
@Override
void onAutomaticRuleStatusChanged(int userId, String pkg, String id, int status) {
Binder.withCleanCallingIdentity(() -> {
Intent intent = new Intent(ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED);
intent.setPackage(pkg);
intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, id);
intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, status);
getContext().sendBroadcastAsUser(intent, UserHandle.of(userId));
});
}
});
mPreferencesHelper = new PreferencesHelper(getContext(),
mPackageManagerClient,
mRankingHandler,
mZenModeHelper,
new NotificationChannelLoggerImpl(),
mAppOps,
new SysUiStatsEvent.BuilderFactory());
mRankingHelper = new RankingHelper(getContext(),
mRankingHandler,
mPreferencesHelper,
mZenModeHelper,
mUsageStats,
extractorNames);
mSnoozeHelper = snoozeHelper;
mGroupHelper = groupHelper;
mHistoryManager = historyManager;
// This is a ManagedServices object that keeps track of the listeners.
mListeners = notificationListeners;
// This is a MangedServices object that keeps track of the assistant.
mAssistants = notificationAssistants;
// Needs to be set before loadPolicyFile
mAllowedManagedServicePackages = this::canUseManagedServices;
mPolicyFile = policyFile;
loadPolicyFile();
mStatusBar = getLocalService(StatusBarManagerInternal.class);
if (mStatusBar != null) {
mStatusBar.setNotificationDelegate(mNotificationDelegate);
}
mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
mFallbackVibrationPattern = getLongArray(resources,
R.array.config_notificationFallbackVibePattern,
VIBRATE_PATTERN_MAXLEN,
DEFAULT_VIBRATE_PATTERN);
mInCallNotificationUri = Uri.parse("file://" +
resources.getString(R.string.config_inCallNotificationSound));
mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
.build();
mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
mHasLight =
resources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed);
// Don't start allowing notifications until the setup wizard has run once.
// After that, including subsequent boots, init with notifications turned on.
// This works on the first boot because the setup wizard will toggle this
// flag at least once and we'll go back to 0 after that.
if (0 == Settings.Global.getInt(getContext().getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0)) {
mDisableNotificationEffects = true;
}
mZenModeHelper.initZenMode();
mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
mUserProfiles.updateCache(getContext());
telephonyManager.listen(new PhoneStateListener() {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
if (mCallState == state) return;
if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
mCallState = state;
}
}, PhoneStateListener.LISTEN_CALL_STATE);
mSettingsObserver = new SettingsObserver(mHandler);
mArchive = new Archive(resources.getInteger(
R.integer.config_notificationServiceArchiveSize));
mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
|| mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
mIsAutomotive =
mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0);
mNotificationEffectsEnabledForAutomotive =
resources.getBoolean(R.bool.config_enableServerNotificationEffectsForAutomotive);
mPreferencesHelper.lockChannelsForOEM(getContext().getResources().getStringArray(
com.android.internal.R.array.config_nonBlockableNotificationPackages));
mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray(
com.android.internal.R.array.config_priorityOnlyDndExemptPackages));
mWarnRemoteViewsSizeBytes = getContext().getResources().getInteger(
com.android.internal.R.integer.config_notificationWarnRemoteViewSizeBytes);
mStripRemoteViewsSizeBytes = getContext().getResources().getInteger(
com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes);
mMsgPkgsAllowedAsConvos = Set.of(getStringArrayResource(
com.android.internal.R.array.config_notificationMsgPkgsAllowedAsConvos));
mStatsManager = statsManager;
}
private NotificationListeners mListeners; 这个变量比较重要,用于管理通知的接收者.
public class NotificationListeners extends ManagedServices
2.System UI的启动流程
SystemServer.Java
private static void startSystemUi(Context context, WindowManagerService windowManager) {
PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
Intent intent = new Intent();
intent.setComponent(pm.getSystemUiServiceComponent());
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
//Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.SYSTEM);
windowManager.onSystemUiStarted();
}
SystemUIService.java
@Inject
public SystemUIService(
@Main Handler mainHandler,
DumpHandler dumpHandler,
BroadcastDispatcher broadcastDispatcher,
LogBufferFreezer logBufferFreezer) {
super();
mMainHandler = mainHandler;
mDumpHandler = dumpHandler;
mBroadcastDispatcher = broadcastDispatcher;
mLogBufferFreezer = logBufferFreezer;
}
@Override
public void onCreate() {
super.onCreate();
// Start all of SystemUI
((SystemUIApplication) getApplication()).startServicesIfNeeded();
// Finish initializing dump logic
mLogBufferFreezer.attach(mBroadcastDispatcher);
// For debugging RescueParty
if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_sysui", false)) {
throw new RuntimeException();
}
if (Build.IS_DEBUGGABLE) {
// b/71353150 - looking for leaked binder proxies
BinderInternal.nSetBinderProxyCountEnabled(true);
BinderInternal.nSetBinderProxyCountWatermarks(1000,900);
BinderInternal.setBinderProxyCountCallback(
new BinderInternal.BinderProxyLimitListener() {
@Override
public void onLimitReached(int uid) {
Slog.w(SystemUIApplication.TAG,
"uid " + uid + " sent too many Binder proxies to uid "
+ Process.myUid());
}
}, mMainHandler);
}
// Bind the dump service so we can dump extra info during a bug report
startServiceAsUser(
new Intent(getApplicationContext(), SystemUIAuxiliaryDumpService.class),
UserHandle.SYSTEM);
}
SystemUIApplication.java
/**
* Makes sure that all the SystemUI services are running. If they are already running, this is a
* no-op. This is needed to conditinally start all the services, as we only need to have it in
* the main process.
* <p>This method must only be called from the main thread.</p>
*/
public void startServicesIfNeeded() {
String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
}
private void startServicesIfNeeded(String metricsPrefix, String[] services) {
mServices = new SystemUI[services.length];
final int N = services.length;
for (int i = 0; i < N; i++) {
String clsName = services[i];
if (DEBUG) Log.d(TAG, "loading: " + clsName);
log.traceBegin(metricsPrefix + clsName);
long ti = System.currentTimeMillis();
try {
SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
if (obj == null) {
Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
obj = (SystemUI) constructor.newInstance(this);
}
mServices[i] = obj;
} catch (ClassNotFoundException
| NoSuchMethodException
| IllegalAccessException
| InstantiationException
| InvocationTargetException ex) {
throw new RuntimeException(ex);
}
if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
mServices[i].start();
log.traceEnd();
}
}
SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
获取SystemUI 中配置的组件,通过反射创建并调用start().
我们只关注StausBar
StatusBar.java
@Override
public void start() {
createAndAddWindows(result);
// Set up the initial notification state. This needs to happen before
setUpPresenter();
}
private void setUpPresenter() {
// Set up the initial notification state.
mNotificationsController.initialize(
this,
mPresenter,
(NotificationListContainer) mStackScroller,
mNotificationActivityStarter,
mPresenter);
}
初始化NotificationsController
NotificationsController 是一个接口 NotificationsControllerImpl 实现了该接口.
NotificationsControllerImpl.kt
override fun initialize(
statusBar: StatusBar,
presenter: NotificationPresenter,
listContainer: NotificationListContainer,
notificationActivityStarter: NotificationActivityStarter,
bindRowCallback: NotificationRowBinderImpl.BindRowCallback
) {
notificationListener.registerAsSystemService()
}
NotificationListener.java
public void registerAsSystemService() {
try {
registerAsSystemService(mContext,
new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
UserHandle.USER_ALL);
} catch (RemoteException e) {
Log.e(TAG, "Unable to register notification listener", e);
}
}
public class NotificationListener extends NotificationListenerWithPlugins
public class NotificationListenerWithPlugins extends NotificationListenerService implements
PluginListener<NotificationListenerController> {
NotificationListener 继承 NotificationListenerWithPlugins 继承NotificationListenerService
最终会调用NotificationListenerService 的 registerAsSystemService 方法.
NotificationListenerWithPlugins..java
public void registerAsSystemService(Context context, ComponentName componentName,
int currentUser) throws RemoteException {
super.registerAsSystemService(context, componentName, currentUser);
Dependency.get(PluginManager.class).addPluginListener(this,
NotificationListenerController.class);
}
NotificationListenerService.java
@SystemApi
public void registerAsSystemService(Context context, ComponentName componentName,
int currentUser) throws RemoteException {
if (mWrapper == null) {
mWrapper = new NotificationListenerWrapper();
}
mSystemContext = context;
INotificationManager noMan = getNotificationInterface();
mHandler = new MyHandler(context.getMainLooper());
mCurrentUser = currentUser;
noMan.registerListener(mWrapper, componentName, currentUser);
}
protected class NotificationListenerWrapper extends INotificationListener.Stub {
NotificationListenerWrapper是NotificationListenerService的内部类 并实现了INotificationListener.Stub.
创建NotificationListenerWrapper并将其注册到NMS .
以上SystemUI启动后将INotificationListener的代理对象注册到了NMS 中.SystemUI 部分流程告一段落.接着回到NMS中.
NotificaionManagerService.java
/**
* Register a listener binder directly with the notification manager.
*
* Only works with system callers. Apps should extend
* {@link android.service.notification.NotificationListenerService}.
*/
@Override
public void registerListener(final INotificationListener listener,
final ComponentName component, final int userid) {
enforceSystemOrSystemUI("INotificationManager.registerListener");
mListeners.registerSystemService(listener, component, userid);
}
mListeners 就是前面提到的NotificationListeners
ManagedServices.java
public class NotificationListeners extends ManagedServices
public void registerSystemService(IInterface service, ComponentName component, int userid) {
checkNotNull(service);
ManagedServiceInfo info = registerServiceImpl(
service, component, userid, Build.VERSION_CODES.CUR_DEVELOPMENT);
if (info != null) {
onServiceAdded(info);
}
}
private ManagedServiceInfo registerServiceImpl(final IInterface service,
final ComponentName component, final int userid, int targetSdk) {
ManagedServiceInfo info = newServiceInfo(service, component, userid,
true /*isSystem*/, null /*connection*/, targetSdk);
return registerServiceImpl(info);
}
private ManagedServiceInfo newServiceInfo(IInterface service,
ComponentName component, int userId, boolean isSystem, ServiceConnection connection,
int targetSdkVersion) {
return new ManagedServiceInfo(service, component, userId, isSystem, connection,
targetSdkVersion);
}
ManagedServiceInfo 是 ManagedServices 内部类
public class ManagedServiceInfo implements IBinder.DeathRecipient {
public IInterface service;
public ComponentName component;
public int userid;
public boolean isSystem;
public ServiceConnection connection;
public int targetSdkVersion;
public ManagedServiceInfo(IInterface service, ComponentName component,
int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion) {
this.service = service;
this.component = component;
this.userid = userid;
this.isSystem = isSystem;
this.connection = connection;
this.targetSdkVersion = targetSdkVersion;
}
public IInterface service; 指向的就是前面提到的NotificationListenerWrapper对象.是一个代理对象.该对象运行在SystemUi中用于接收通知.
// contains connections to all connected services, including app services
// and system services
private final ArrayList<ManagedServiceInfo> mServices = new ArrayList<>();
private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) {
synchronized (mMutex) {
try {
info.service.asBinder().linkToDeath(info, 0);
mServices.add(info);
return info;
} catch (RemoteException e) {
// already dead
}
}
return null;
}
至此SystemUi 注册监听器的流程结束.
3.应用层发通知的流程
应用层创建Notification NotificationChannel 通过NotificationManger.notifi方法就可以发通知了.
NotificationManger.java
public void notify(int id, Notification notification)
{
notify(null, id, notification);
}
public void notify(String tag, int id, Notification notification)
{
notifyAsUser(tag, id, notification, mContext.getUser());
}
/**
* @hide
*/
@UnsupportedAppUsage
public void notifyAsUser(String tag, int id, Notification notification, UserHandle user)
{
INotificationManager service = getService();
String pkg = mContext.getPackageName();
try {
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
fixNotification(notification), user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
最终会调用NMS 的enqueueNotificationWithTag 方法
NMS->
@Override
public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Notification notification, int userId) throws RemoteException {
enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Binder.getCallingPid(), tag, id, notification, userId);
}
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);
}
void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
final StatusBarNotification n = new StatusBarNotification(
pkg, opPkg, id, tag, notificationUid, callingPid, notification,
user, null, System.currentTimeMillis());
final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground));
}
enqueueNotificationInternal 该方法会做一些权限 参数 是否是前台服务的通知 检查 .
主要是创建StatusBarNotificaiton 和 NotificationRecord 通过handler 发送一个异步消息
final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
protected class EnqueueNotificationRunnable implements Runnable {
private final NotificationRecord r;
private final int userId;
private final boolean isAppForeground;
EnqueueNotificationRunnable(int userId, NotificationRecord r, boolean foreground) {
this.userId = userId;
this.r = r;
this.isAppForeground = foreground;
}
@Override
public void run() {
synchronized (mNotificationLock) {
mEnqueuedNotifications.add(r);
final StatusBarNotification n = r.getSbn();
NotificationRecord old = mNotificationsByKey.get(n.getKey());
if (old != null) {
// Retain ranking information from previous record
r.copyRankingInformation(old);
}
// Handle grouped notifications and bail out early if we
// can to avoid extracting signals.
handleGroupedNotificationLocked(r, old, callingUid, callingPid);
mHandler.post(new PostNotificationRunnable(r.getKey()));
}
}
}
将NotificationRecord 添加到mEnqueuedNotifications 集合当中.并通过key 查找是否有之前发送的旧的通知.如果有就拷贝旧的通知排序信息.将通知通过key 进程分组.再次发送一个异步消息.
看下 StatusBarNotification.Java 的 key 和 groupkey
private String key() {
String sbnKey = user.getIdentifier() + "|" + pkg + "|" + id + "|" + tag + "|" + uid;
if (overrideGroupKey != null && getNotification().isGroupSummary()) {
sbnKey = sbnKey + "|" + overrideGroupKey;
}
return sbnKey;
}
private String groupKey() {
if (overrideGroupKey != null) {
return user.getIdentifier() + "|" + pkg + "|" + "g:" + overrideGroupKey;
}
final String group = getNotification().getGroup();
final String sortKey = getNotification().getSortKey();
if (group == null && sortKey == null) {
// a group of one
return key;
}
return user.getIdentifier() + "|" + pkg + "|" +
(group == null
? "c:" + notification.getChannelId()
: "g:" + group);
}
protected class PostNotificationRunnable implements Runnable {
private final String key;
PostNotificationRunnable(String key) {
this.key = key;
}
@Override
public void run() {
synchronized (mNotificationLock) {
try {
NotificationRecord r = null;
int N = mEnqueuedNotifications.size();
for (int i = 0; i < N; i++) {
final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
if (Objects.equals(key, enqueued.getKey())) {
r = enqueued;
break;
}
}
NotificationRecord old = mNotificationsByKey.get(key);
final StatusBarNotification n = r.getSbn();
final Notification notification = n.getNotification();
// Make sure the SBN has an instance ID for statsd logging.
if (old == null || old.getSbn().getInstanceId() == null) {
n.setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
} else {
n.setInstanceId(old.getSbn().getInstanceId());
}
int index = indexOfNotificationLocked(n.getKey());
if (index < 0) {
mNotificationList.add(r);
mUsageStats.registerPostedByApp(r);
r.setInterruptive(isVisuallyInterruptive(null, r));
} else {
old = mNotificationList.get(index);
// Potentially *changes* old
mNotificationList.set(index, r);
mUsageStats.registerUpdatedByApp(r, old);
// Make sure we don't lose the foreground service state.
notification.flags |=
old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
r.isUpdate = true;
final boolean isInterruptive = isVisuallyInterruptive(old, r);
r.setTextChanged(isInterruptive);
r.setInterruptive(isInterruptive);
}
mNotificationsByKey.put(n.getKey(), r);
// Ensure if this is a foreground service that the proper additional
// flags are set.
if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
notification.flags |= FLAG_ONGOING_EVENT
| FLAG_NO_CLEAR;
}
mRankingHelper.extractSignals(r);
mRankingHelper.sort(mNotificationList);
final int position = mRankingHelper.indexOf(mNotificationList, r);
int buzzBeepBlinkLoggingCode = 0;
if (!r.isHidden()) {
buzzBeepBlinkLoggingCode = buzzBeepBlinkLocked(r);
}
if (notification.getSmallIcon() != null) {
StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null;
mListeners.notifyPostedLocked(r, old);
if ((oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup()))
&& !isCritical(r)) {
mHandler.post(new Runnable() {
@Override
public void run() {
mGroupHelper.onNotificationPosted(
n, hasAutoGroupSummaryLocked(n));
}
});
} else if (oldSbn != null) {
final NotificationRecord finalRecord = r;
mHandler.post(() -> mGroupHelper.onNotificationUpdated(
finalRecord.getSbn(), hasAutoGroupSummaryLocked(n)));
}
} else {
Slog.e(TAG, "Not posting notification without small icon: " + notification);
if (old != null && !old.isCanceled) {
mListeners.notifyRemovedLocked(r,
NotificationListenerService.REASON_ERROR, r.getStats());
mHandler.post(new Runnable() {
@Override
public void run() {
mGroupHelper.onNotificationRemoved(n);
}
});
}
// ATTENTION: in a future release we will bail out here
// so that we do not play sounds, show lights, etc. for invalid
// notifications
Slog.e(TAG, "WARNING: In a future release this will crash the app: "
+ n.getPackageName());
}
if (mShortcutHelper != null) {
mShortcutHelper.maybeListenForShortcutChangesForBubbles(r,
false /* isRemoved */,
mHandler);
}
maybeRecordInterruptionLocked(r);
maybeRegisterMessageSent(r);
// Log event to statsd
mNotificationRecordLogger.maybeLogNotificationPosted(r, old, position,
buzzBeepBlinkLoggingCode, getGroupInstanceId(n.getGroupKey()));
} finally {
int N = mEnqueuedNotifications.size();
for (int i = 0; i < N; i++) {
final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
if (Objects.equals(key, enqueued.getKey())) {
mEnqueuedNotifications.remove(i);
break;
}
}
}
}
}
}
通过Key在集合找到当前通知,并检查是否有旧的通知.如果有则继承旧的同通知InstanceId 和FLAG_FOREGROUND_SERVICE flag
如果通知是前台服务添加FLAG_ONGOING_EVENT 和 FLAG_NO_CLEAR 标识。
并进行排序。Android 5.0 后 通知必须设置比SmallIcon。这个icon用于显示在状态栏上的通知区域。该图标不可有颜色通道。
最终调用mListeners.notifyPostedLocked(r, old);
@GuardedBy("mNotificationLock")
private void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
boolean notifyAllListeners) {
try {
// Lazily initialized snapshots of the notification.
StatusBarNotification sbn = r.getSbn();
StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null;
TrimCache trimCache = new TrimCache(sbn);
for (final ManagedServiceInfo info : getServices()) {
boolean sbnVisible = isVisibleToListener(sbn, info);
boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info)
: false;
// This notification hasn't been and still isn't visible -> ignore.
if (!oldSbnVisible && !sbnVisible) {
continue;
}
// If the notification is hidden, don't notifyPosted listeners targeting < P.
// Instead, those listeners will receive notifyPosted when the notification is
// unhidden.
if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
continue;
}
// If we shouldn't notify all listeners, this means the hidden state of
// a notification was changed.
Don't notifyPosted listeners targeting >= P.
// Instead, those listeners will receive notifyRankingUpdate.
if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) {
continue;
}
final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
// This notification became invisible -> remove the old one.
if (oldSbnVisible && !sbnVisible) {
final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
mHandler.post(new Runnable() {
@Override
public void run() {
notifyRemoved(
info, oldSbnLightClone, update, null, REASON_USER_STOPPED);
}
});
continue;
}
// Grant access before listener is notified
final int targetUserId = (info.userid == UserHandle.USER_ALL)
? UserHandle.USER_SYSTEM : info.userid;
updateUriPermissions(r, old, info.component.getPackageName(), targetUserId);
final StatusBarNotification sbnToPost = trimCache.ForListener(info);
mHandler.post(new Runnable() {
@Override
public void run() {
notifyPosted(info, sbnToPost, update);
}
});
}
} catch (Exception e) {
Slog.e(TAG, "Could not notify listeners for " + r.getKey(), e);
}
}
判断通知的可见性如果旧的通知可见而当前通知不可见则移除旧的通知
private void notifyPosted(final ManagedServiceInfo info,
final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
final INotificationListener listener = (INotificationListener) info.service;
StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
try {
listener.onNotificationPosted(sbnHolder, rankingUpdate);
} catch (RemoteException ex) {
Slog.e(TAG, "unable to notify listener (posted): " + info, ex);
}
}
listener 则是NotificationListenerService 内部类 NotificationListenerWrapper的对象 他的对端是运行在SystemUi。
NotificationListenerWrapper.java
public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
NotificationRankingUpdate update) {
StatusBarNotification sbn;
try {
sbn = sbnHolder.get();
} catch (RemoteException e) {
Log.w(TAG, "onNotificationPosted: Error receiving StatusBarNotification", e);
return;
}
if (sbn == null) {
Log.w(TAG, "onNotificationPosted: Error receiving StatusBarNotification");
return;
}
try {
// convert icon metadata to legacy format for older clients
createLegacyIconExtras(sbn.getNotification());
maybePopulateRemoteViews(sbn.getNotification());
maybePopulatePeople(sbn.getNotification());
} catch (IllegalArgumentException e) {
// warn and drop corrupt notification
Log.w(TAG, "onNotificationPosted: can't rebuild notification from " +
sbn.getPackageName());
sbn = null;
}
// protect subclass from concurrent modifications of (@link mNotificationKeys}.
synchronized (mLock) {
applyUpdateLocked(update);
if (sbn != null) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = sbn;
args.arg2 = mRankingMap;
mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_POSTED,
args).sendToTarget();
} else {
// still pass along the ranking map, it may contain other information
mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_RANKING_UPDATE,
mRankingMap).sendToTarget();
}
}
}
设置icon ,remoteView 和 EXTRA_PEOPLE 发送异步消息 MSG_ON_NOTIFICATION_POSTED
public void handleMessage(Message msg) {
if (!isConnected) {
return;
}
switch (msg.what) {
case MSG_ON_NOTIFICATION_POSTED: {
SomeArgs args = (SomeArgs) msg.obj;
StatusBarNotification sbn = (StatusBarNotification) args.arg1;
RankingMap rankingMap = (RankingMap) args.arg2;
args.recycle();
onNotificationPosted(sbn, rankingMap);
} break;
/**
* Implement this method to learn about new notifications as they are posted by apps.
*
* @param sbn A data structure encapsulating the original {@link android.app.Notification}
*
object as well as its identifying information (tag and id) and source
*
(package name).
* @param rankingMap The current ranking map that can be used to retrieve ranking information
*
for active notifications, including the newly posted one.
*/
public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
onNotificationPosted(sbn);
}
最终会调用NotificationListenerService 的实现类。即 NotificationListener
com.android.systemui.statusbar.NotificationListener
@Override
public void onNotificationPosted(final StatusBarNotification sbn,
final RankingMap rankingMap) {
if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
if (sbn != null && !onPluginNotificationPosted(sbn, rankingMap)) {
mMainHandler.post(() -> {
processForRemoteInput(sbn.getNotification(), mContext);
for (NotificationHandler handler : mNotificationHandlers) {
handler.onNotificationPosted(sbn, rankingMap);
}
});
}
}
总结:
SystemServer启动NMS 和SystemUI后SystemUI注册通知监听器到NMS后。应用发送通知到NMS由NMS处理排序后交给SystemUI。最终由SystemUI显示出来。
最后
以上就是兴奋石头为你收集整理的NotificationManagerService流程梳理的全部内容,希望文章能够帮你解决NotificationManagerService流程梳理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复