Service的Context介绍

Android  源码分析  2023年12月9日 pm12:12发布12个月前更新 城堡大人
121 0 0

前言

对于Application,Activity和Service这几个类,我们是很[熟悉]的。确实[熟悉],作为App开发这基本都要面对这几个类。

几天记录一下Service的Context创建,其实也就是简单的说说。

正文

Context的使用场景

  1. 使用Context调用方法,比如启动Activity、访问资源、调用系统级服务等。

  2. 调用方法时传入Context,比如弹出Toast、创建Dialog等。

Context意为[上下文],也是Application,Activity和ServiceContext的祖先类。

Application -> ContextWrapper -> Context;
Activity -> ContextThemeWrapper -> ContextWrapper -> Context
Service -> ContextWrapper -> Context

或者看图,图上更详细

Service的Context介绍

通过源码发现,Context其实也不干活的,具体干活的是ContextImpl。

今天就介绍一下Service的Context。

这部分在《startService()源码分析》介绍了,而且Service的Context创建跟《Activity的Context介绍》一样的。

不过为了单独记录,这里也单独抽出来说一下。(反正流水文,凑个字数)

接《startService()源码分析》,进程创建成功后,ActivityThread.main()-->attach()-->ActivityManagerService.attachApplication()。

我们从ActivityManagerService.java中开始跟。

ActivityManagerService.java

attachApplication()
@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
    synchronized (this) {
        //略
        attachApplicationLocked(thread, callingPid, callingUid, startSeq);
        //略
    }
}
attachApplicationLocked()
@GuardedBy("this")
private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
    //略
    final String processName = app.processName;
    try {
        AppDeathRecipient adr = new AppDeathRecipient(app, pid, thread);
        //binder死亡监听
        thread.asBinder().linkToDeath(adr, 0);
        app.deathRecipient = adr;
    } catch (RemoteException e) {
        app.resetPackageList(mProcessStats);
        startProcessLocked(app, "link fail", processName);
        return false;
    }
    //略
    try {
        //略
        //isolatedEntryPoint为null
        if (app.isolatedEntryPoint != null) {
            thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);
        } else if (app.instr != null) {
            //略
        } else {
            //[重1]绑定bindApplication
            //通过Handler处理,主要是执行Application的onCreate()方法。
            //这里不会阻塞!!!
            thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                    null, null, null, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(getGlobalConfiguration()), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked(),
                    buildSerial, isAutofillCompatEnabled);
        }
        //略
    } catch (Exception e) {
        //略
        return false;
    }
    //略
    boolean badApp = false;
    boolean didSomething = false;
    //启动Activity 
    if (normalMode) {
        try {
            //重点启动Activity相关
            if (mStackSupervisor.attachApplicationLocked(app)) {
                didSomething = true;
            }
        } catch (Exception e) {
            badApp = true;
        }
    }
    //启动服务
    if (!badApp) {
        try {
            //[重2],启动服务
            didSomething |= mServices.attachApplicationLocked(app, processName);
            checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
        } catch (Exception e) {
            badApp = true;
        }
    }
    //启动广播
    if (!badApp && isPendingBroadcastProcessLocked(pid)) {
        try {
            //重点
            didSomething |= sendPendingBroadcastsLocked(app);
        } catch (Exception e) {
            badApp = true;
        }
    }
    //略
    return true;
}

这个attachApplicationLocked()很重要。

  1. 创建Application

  2. 如果需要,启动Activity

  3. 如果需要,启动Service

  4. 如果需要,发送广播(应该是静态广播,暂时没跟,后续分析)

这里我们关注Service的启动

if (!badApp) {
    try {
        didSomething |= mServices.attachApplicationLocked(app, processName);
    } catch (Exception e) {
        badApp = true;
    }
}

ActiveServices.java

attachApplicationLocked()
boolean attachApplicationLocked(ProcessRecord proc, String processName)
        throws RemoteException {
    boolean didSomething = false;
    //Pending中的服务,这里大于0
    if (mPendingServices.size() > 0) {
        ServiceRecord sr = null;
        try {
            for (int i=0; i<mPendingServices.size(); i++) {
                sr = mPendingServices.get(i);
                //sr就是上面保存的Service信息
                //ServiceRecord{66fcbc0 u0 com.biumall.biuaidlserver/.server.DemoService}
                if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
                        || !processName.equals(sr.processName))) {
                    continue;
                }
                //找到了,先移除mPendingServices
                mPendingServices.remove(i);
                i--;
                proc.addPackage(sr.appInfo.packageName, sr.appInfo.longVersionCode,
                        mAm.mProcessStats);
                //[重]启动服务,看包名就知道啥意思哈
                realStartServiceLocked(sr, proc, sr.createdFromFg);
                didSomething = true;
                if (!isServiceNeededLocked(sr, false, false)) {
                    bringDownServiceLocked(sr);
                }
            }
        } catch (RemoteException e) {
            throw e;
        }
    }
    //重新启动的服务为0
    if (mRestartingServices.size() > 0) {
        //略
    }
    return didSomething;
}
realStartServiceLocked()

哈哈,命名给力,但,也是调用ActivityThread来创建。。

private final void realStartServiceLocked(ServiceRecord r,
        ProcessRecord app, boolean execInFg) throws RemoteException {
    //略
    //记录是否创建成功
    boolean created = false;
    try {
        //略
        //创建服务的启动
        app.thread.scheduleCreateService(r, r.serviceInfo,
                mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                app.repProcState);
        r.postNotification();
        //只要不异常,这里表示创建成功
        created = true;
    } catch (DeadObjectException e) {
        mAm.appDiedLocked(app);
        throw e;
    } finally {
        //略
    }
    //略 
}

这里只关注服务的创建,其他的不关心哈。

ActivityThread.java

scheduleCreateService()
public final void scheduleCreateService(IBinder token,
        ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
    updateProcessState(processState, false);
    CreateServiceData s = new CreateServiceData();
    s.token = token;
    s.info = info;
    s.compatInfo = compatInfo;
    //发送CREATE_SERVICE
    sendMessage(H.CREATE_SERVICE, s);
}
handleMessage()
case CREATE_SERVICE:
    //处理创建服务
    handleCreateService((CreateServiceData)msg.obj);1
    break;
case BIND_SERVICE:
handleCreateService()
private void handleCreateService(CreateServiceData data) {
    //略
    //获取LoadedApk对象
    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);
    Service service = null;
    try {
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        //创建Service对象
        service = packageInfo.getAppFactory()
                .instantiateService(cl, data.info.name, data.intent);
    } catch (Exception e) {
        if (!mInstrumentation.onException(service, e)) {
            throw new RuntimeException(
                "Unable to instantiate service " + data.info.name
                + ": " + e.toString(), e);
        }
    }

    try {
        //创建Service的Context
        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
        //这里也赋值了
        context.setOuterContext(service);
        //创建Application[仅仅获取而已,之前有创建过]
        Application app = packageInfo.makeApplication(false, mInstrumentation);
        //service 绑定context
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManager.getService());
        //调用Service的onCreate()
        service.onCreate();
        mServices.put(data.token, service);
        try {
            ActivityManager.getService().serviceDoneExecuting(
                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(service, e)) {
            throw new RuntimeException(
                "Unable to create service " + data.info.name
                + ": " + e.toString(), e);
        }
    }
}

这才是真正的创建Service。

  1. 创建Service

  2. 创建ContextImpl

  3. 获取Application

  4. service.attach()

  5. 调用service.onCreate()

跟Activity一样的方式。

至此,Service的Context也创建完成了。

参考文章

  1. startService()源码分析

 历史上的今天

  1. 2022: Android设置语言偏好后应用没有获取对设置的语言(0条评论)
  2. 2021: Android TV 应用中焦点的简单介绍(0条评论)
  3. 2020: [摘]Android 系统重启原因分析(0条评论)
版权声明 1、 本站名称: 笔友城堡
2、 本站网址: https://www.biumall.com/
3、 本站部分文章来源于网络,仅供学习与参考,如有侵权,请留言

暂无评论

暂无评论...

随机推荐

沈从文 : 独处

在我一个自传里,我曾经提到过水给我种种的印象。檐溜、小小的河流、汪洋万顷的大海,莫不对于我有过极大的帮助。我学会用小小脑子去思索一切,全亏得是水。我对于宇宙认识得深一点,也亏得是水。“孤独一点,在你缺少一切的时节,你就会发现,原来还有个你自己。”这是一句真话。我有我自己的生活与理想,可以说是...

shell脚本if中的-e介绍

前言简单记录一下shell脚本if中的-e的作用。记录于此,方便自己查阅。正文-e使用-e filename 如果 filename存在,则为真来个简单的例子#!/bin/bashif [ -e /proc/cpuinfo ];then echo "存在"else...

MediaMetadataRetriever解析媒体文件元数据

前言记录一下,一般获取视频、音频等媒体文件的元数据信息是使用MediaMetadataRetriever这个类。正文直接上代码。MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();//设...

Android双屏异显(Presentation)的简单使用

前言Android 从4.2开始支持双屏显示,支持版本为17以上。Android 双屏原理说白了,自定义一个Presentation类,Android 的标准实现是使用 API Presentation 来实现异显的功能。public class Presentation extends D...

西贝:路人

不知为何,明明想和你说话。却骗你说,风雨正好,该去写点诗句。 不必嘲讽我,你笑出声来,我也当是天籁。 不必怀有敌意,你所有心计,我都当是你对我的心意。 我的宿命分两段,未遇见你时,和遇见你以后。你治好我的忧郁,而后赐我悲伤。 忧郁和悲...

蒋勋:人生,即是修行

选择修行的空间人类的空间感是非常奇怪的东西。过去的人从西门町走路到北门,再从北门走到南门,就是台北市的范围了。可是今日你问任何一个小学生,他都会觉得很近,他坐上公交车、地铁就可以到更远的地方。人类在整个工业革命之后,空间不断在扩大。我自己读完大学,要留学的时候,坐飞机还是一件大事,做这件事情之...