比如在android设备启动后,想在开机后起个服务,但又不想去直接接收Bootcompleted广播,因为广播接收者比较多,可能轮到你那个service处理的时候就比较晚了,所以还是修改源码看看。 修改ActivityManagerService.java的finishBooting函数,在这里去启动想要的服务。
final void finishBooting() {
...
编译services.jar后推进设备,发现会报错
08-24 10:57:07.116: W/ContextImpl(4881): Calling a method in the system process without a qualified user:
android.app.ContextImpl.startService:1531
com.android.server.am.ActivityManagerService.finishBooting:8117
com.android.server.am.ActivityManagerService.bootAnimationComplete:8134
com.android.server.wm.WindowManagerService.performEnableScreen:3482
com.android.server.wm.WindowManagerService.access$1100:274
08-24 10:57:07.116: V/ActivityManager(4881): *** startService: Intent { cmp=com.example.servicedemo/.xxx} type=null fg=false
08-24 10:57:07.116: V/ActivityManager(4881): startService: Intent { cmp=com.example.servicedemo/.xxx} type=null args=null
08-24 10:57:07.116: V/ActivityManager(4881): retrieveServiceLocked: Intent { cmp=com.example.servicedemo/.xxx} type=null callingUid=1000 userId = 0
08-24 10:57:07.116: W/System.err(4881): java.lang.Exception: retrieveServiceLocked
08-24 10:57:07.117: W/System.err(4881): at com.android.server.am.ActiveServices.retrieveServiceLocked(ActiveServices.java:1875)
08-24 10:57:07.117: W/System.err(4881): at com.android.server.am.ActiveServices.startServiceLocked(ActiveServices.java:410)
08-24 10:57:07.117: W/System.err(4881): at com.android.server.am.ActivityManagerService.startService(ActivityManagerService.java:20381)
08-24 10:57:07.117: W/System.err(4881): at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1562)
08-24 10:57:07.117: W/System.err(4881): at android.app.ContextImpl.startService(ContextImpl.java:1532)
08-24 10:57:07.117: W/System.err(4881): at com.android.server.am.ActivityManagerService.finishBooting(ActivityManagerService.java:8117)
08-24 10:57:07.117: W/System.err(4881): at com.android.server.am.ActivityManagerService.bootAnimationComplete(ActivityManagerService.java:8134)
08-24 10:57:07.117: W/System.err(4881): at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3482)
08-24 10:57:07.117: W/System.err(4881): at com.android.server.wm.WindowManagerService.access$1100(WindowManagerService.java:274)
08-24 10:57:07.117: W/System.err(4881): at com.android.server.wm.WindowManagerService$H.handleMessage(WindowManagerService.java:4962)
08-24 10:57:07.117: W/System.err(4881): at android.os.Handler.dispatchMessage(Handler.java:106)
08-24 10:57:07.117: W/System.err(4881): at android.os.Looper.loop(Looper.java:193)
08-24 10:57:07.117: W/System.err(4881): at android.os.HandlerThread.run(HandlerThread.java:65)
08-24 10:57:07.117: W/System.err(4881): at com.android.server.ServiceThread.run(ServiceThread.java:44)
08-24 10:57:07.117: V/ActivityManager(4881): userId = 0
08-24 10:57:07.118: W/ActivityManager(4881): Unable to start service Intent { cmp=com.example.servicedemo/.BootService } U=0: not found
报错找不到这个服务,出错的代码调用地方在ActiveServices.java
private ServiceLookupResult retrieveServiceLocked(Intent service,
String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
boolean allowInstant) {
...
if (r == null) {
try {
...
ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
resolvedType, flags, userId, callingUid);
ServiceInfo sInfo =
rInfo != null ? rInfo.serviceInfo : null;
if (sInfo == null) {
Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId +
": not found");
return null;
}
...
}
rInfo返回值为null导致的,继续追一下代码,看这个调用也能猜到是PackageManagerService.java中的函数
ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
resolvedType, flags, userId, callingUid);
果然是
@Override
public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
final int callingUid = Binder.getCallingUid();
return resolveServiceInternal(intent, resolvedType, flags, userId, callingUid);
}
通过添加log确认以下代码,query的size返回为0,导致返回null
private ResolveInfo resolveServiceInternal(Intent intent, String resolvedType, int flags,
int userId, int callingUid) {
if (!sUserManager.exists(userId)) return null;
flags = updateFlagsForResolve(
flags, userId, intent, callingUid, false );
List<ResolveInfo> query = queryIntentServicesInternal(
intent, resolvedType, flags, userId, callingUid, false );
if (query != null) {
if (query.size() >= 1) {
return query.get(0);
}
}
return null;
}
最后是返回一个list,如果没有走到add添加的话,最后返回肯定是空的了。 通过添加log确认ServiceInfo si返回为null导致
private @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
String resolvedType, int flags, int userId, int callingUid,
boolean includeInstantApps) {
...
if (comp != null) {
final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
final ServiceInfo si = getServiceInfo(comp, flags, userId);
if (si != null) {
...
if (!blockResolution) {
final ResolveInfo ri = new ResolveInfo();
ri.serviceInfo = si;
list.add(ri);
}
}
return list;
...
}
}
最后可以定位到的点是mSettings.isEnabledAndMatchLPr函数为false了
@Override
public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
...
synchronized (mPackages) {
PackageParser.Service s = mServices.mServices.get(component);
if (s != null && mSettings.isEnabledAndMatchLPr(s.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
...
return PackageParser.generateServiceInfo(
s, flags, ps.readUserState(userId), userId);
}
}
return null;
}
最后打log确认是isMatch的结果为false,修改就比较简单了,过滤出我们想要的包名,然后返回true就可以解决这个报错。
boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {
final PackageSetting ps = mPackages.get(componentInfo.packageName);
if (ps == null) return false;
final PackageUserState userState = ps.readUserState(userId);
return userState.isMatch(componentInfo, flags);
}
public boolean isMatch(ComponentInfo componentInfo, int flags) {
...
final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)
&& !componentInfo.directBootAware;
final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
&& componentInfo.directBootAware;
return matchesUnaware || matchesAware;
}
但是,当前测试的service并不能立马能运行起来,接着会遇到另一个错误。
44423 08-24 16:03:08.793 4809 4809 V ActivityManager: Retrieve created new service: ServiceRecord{6882e47 u0 com.example.servicedemo/.xxx}
44424 08-24 16:03:08.793 4809 4809 D ActivityManager: callingPackage = android isBackgroundStartServiceWhiteList = false
44425 08-24 16:03:08.793 4809 4809 W ActivityManager: Background start not allowed: service Intent { flg=0x100 cmp=com.example.xxx/.BootService } to com.example.servicedemo/.BootService from pid=4809 uid=1000 pkg=android startFg?=false
44426 08-24 16:03:08.793 4809 4809 W SystemServer: ***********************************************
44427 08-24 16:03:08.794 4809 4809 E SystemServer: BOOT FAILURE starting service demo
44428 08-24 16:03:08.794 4809 4809 E SystemServer: java.lang.IllegalStateException: Not allowed to start service Intent { flg=0x100 cmp=com.example.servicedemo/.xxx}: app is in background uid null
44429 08-24 16:03:08.794 4809 4809 E SystemServer: at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1577)
44430 08-24 16:03:08.794 4809 4809 E SystemServer: at android.app.ContextImpl.startServiceAsUser(ContextImpl.java:1549)
44431 08-24 16:03:08.794 4809 4809 E SystemServer: at com.android.server.SystemServer.startServiceDemo(SystemServer.java:1965)
44432 08-24 16:03:08.794 4809 4809 E SystemServer: at com.android.server.SystemServer.lambda$startOtherServices$4(SystemServer.java:1802)
44433 08-24 16:03:08.794 4809 4809 E SystemServer: at com.android.server.-$$Lambda$SystemServer$s9erd2iGXiS7bbg_mQJUxyVboQM.run(Unknown Source:53)
44434 08-24 16:03:08.794 4809 4809 E SystemServer: at com.android.server.am.ActivityManagerService.systemReady(ActivityManagerService.java:15258)
44435 08-24 16:03:08.794 4809 4809 E SystemServer: at com.android.server.SystemServer.startOtherServices(SystemServer.java:1751)
44436 08-24 16:03:08.794 4809 4809 E SystemServer: at com.android.server.SystemServer.run(SystemServer.java:433)
44437 08-24 16:03:08.794 4809 4809 E SystemServer: at com.android.server.SystemServer.main(SystemServer.java:296)
44438 08-24 16:03:08.794 4809 4809 E SystemServer: at java.lang.reflect.Method.invoke(Native Method)
44439 08-24 16:03:08.794 4809 4809 E SystemServer: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
44440 08-24 16:03:08.794 4809 4809 E SystemServer: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:838)
44441 08-24 16:03:08.794 4935 4935 I droid.bluetoot: The ClassLoaderContext is a special shared library.
从堆栈打印来看,是报的当前服务不能启动,app是个后台服务,在android O之后不会被允许了。
报错对应的代码在ActiveServices.java中如下位置:
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
throws TransactionTooLargeException {
...
if (forcedStandby || (!r.startRequested && !fgRequired)) {
final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
Slog.w(TAG, "Background start not allowed: service "
+ service + " to " + r.name.flattenToShortString()
+ " from pid=" + callingPid + " uid=" + callingUid
+ " pkg=" + callingPackage + " startFg?=" + fgRequired);
if (allowed == ActivityManager.APP_START_MODE_DELAYED || forceSilentAbort) {
return null;
}
...
知道了报错原因,修改起来就比较简单了,过滤我们的服务包名称,然后allowed返回期望的APP_START_MODE_NORMAL就可以了。
|