IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> android P开机后启动一个service的方法 -> 正文阅读

[移动开发]android P开机后启动一个service的方法

比如在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 {
...
                // TODO: come back and remove this assumption to triage all services
                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 /*includeInstantApps*/);
        List<ResolveInfo> query = queryIntentServicesInternal(
                intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/);
        if (query != null) {
            if (query.size() >= 1) {
                // If there is more than one service with the same priority,
                // just arbitrarily pick the first one.
                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)) {
            // Before going further -- if this app is not allowed to start services in the
            // background, then at this point we aren't going to let it period.
            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) {
                    // In this case we are silently disabling the app, to disrupt as
                    // little as possible existing apps.
                    return null;
                }
				...

知道了报错原因,修改起来就比较简单了,过滤我们的服务包名称,然后allowed返回期望的APP_START_MODE_NORMAL就可以了。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章           查看所有文章
加:2021-08-25 23:45:04  更:2021-08-25 23:45:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:46:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码