2018-12-27
继之前跪在Android N的StrictMode
上了。现在又跪在的Android O 的NotificationChannel上了
场景如下:
某些场景中需要上传图片,选择图片或者拍照时使用系统的图库会将自己的app置于后台,若选择图片的时间过长,则可能会导致自己的app会杀死。看了一下传承下来的代码,是在这种情况下发送一个前台通知startForeground
,使此服务在前台运行。但是会在通知栏上显示一个应用正在运行的通知.
源码分析
查看Android 28的源码,发现调用链如下:
首先 Service.java
中调用
public final void startForeground(int id, Notification notification) {
try {
mActivityManager.setServiceForeground(
new ComponentName(this, mClassName), mToken, id,
notification, 0);
} catch (RemoteException ex) {
}
}
这里的mActivityManager
的声明是private IActivityManager mActivityManager = null;
在这里,IActivityManager
的实现类是ActivityManagerService
@Override
public void setServiceForeground(ComponentName className, IBinder token,
int id, Notification notification, int flags) {
synchronized(this) {
mServices.setServiceForegroundLocked(className, token, id, notification, flags);
}
}
public void setServiceForegroundLocked(ComponentName className, IBinder token,
int id, Notification notification, int flags) {
final int userId = UserHandle.getCallingUserId();
final long origId = Binder.clearCallingIdentity();
try {
ServiceRecord r = findServiceLocked(className, token, userId);
if (r != null) {
setServiceForegroundInnerLocked(r, id, notification, flags);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
finally中调用的Binder方法是一个native方法,主要看一下setServiceForegroundInnerLocked
:
方法太长,关注一下我们需要的
// 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) {
final ServiceMap smap = getServiceMapLocked(r.userId);
if (smap != null) {
ActiveForegroundApp active = smap.mActiveForegroundApps.get(r.packageName);
if (active == null) {
active = new ActiveForegroundApp();
active.mPackageName = r.packageName