Android系统源码分析--Context

Android是一个开源系统,至少说是大部分开源的,源代码的学习对于我们学习Android帮助非常大,可能很多人看看源码时感觉代码太多了,不知道从何开始,今天我就从基本的部分开始跟大家一起学习Android源码。
声明:本篇以及以后Android源码分析是基于Android-7.1.2_r11(7.1版本系统)源码进行分析。如果之后切换会进行声明。希望对照源码学习的要找对应版本进行查看。

在开始介绍Context前我们先看一张Android系统框架层的图:

这里写图片描述

从上面图可以看到Android系统主要分为五层:应用层,应用框架层,Native库和运行环境,硬件抽象层和Linux内核层。本章不重点讲Android系统框架,只是开始给大家展示一下,有个了解,我们先从Framework层开始学习,首先学习Context,下面进入正题。

概述:

做Android开发的朋友在开发过程中时刻用到Context,那么Context到底是什么,到底是做什么的我们详细分析一下。源码中解释Context是一个面向应用全局信息的接口,那么我看看哪些信息与Context有关:

  • 获取AssetManager:getAssets();
  • 获取Resources:getResources();
  • 获取PackageManager:getPackageManager();
  • 获取ContentResolver:getContentResolver();
  • 获取主线程Looper:getMainLooper();
  • 获取Application的Context:getApplicationContext();
  • 获取资源文件:getText,getString,getColor,getDrawable,getColorStateList;
  • 设置主题,获取主题资源id:setTheme,getThemeResId;
  • 获取样式属性TypedArray:obtainStyledAttributes();
  • 获取类加载器ClassLoader:getClassLoader();
  • 获取应用信息对象ApplicationInfo:getApplicationInfo();
  • 获取SharedPreferences:getSharedPreferences();
  • 打开文件FileInputStream:openFileInput();
  • 删除文件:deleteFile();
  • 获取文件File:getFileStreamPath();
  • 打开或者创建数据库:openOrCreateDatabase();
  • 移除或者删除数据库:moveDatabaseFrom(),deleteDatabase();
  • 启动Activity:startActivity(),startActivityAsUser(),startActivityForResult(),startActivities();
  • 注册、发送、注销广播:registerReceiver(),sendBroadcast(),sendOrderedBroadcast(),unregisterReceiver();
  • 启动、绑定、解除绑定、停止服务:startService(),bindService(),unbindService(),stopService();
  • 获取系统服务:getSystemService();
  • 检查权限(Android 6.0以上):checkPermission();
  • 根据应用名创建Context:createPackageContext();
  • 根据应用信息创建Context:createApplicationContext();
  • 获取显示信息对象Display:getDisplay();

主要的信息关联就是这些,还有一些不常用的或者废弃的没有再展示,有兴趣自己看看源码,官方解释很清晰。上面有个获取系统服务,我们下面把所有的系统服务列举一下(前面是服务,后面是获取服务的名称):

  • android.view.WindowManager–#WINDOW_SERVICE—————————–窗口管理
  • android.view.LayoutInflater–#LAYOUT_INFLATER_SERVICE——————-布局加载器
  • android.app.ActivityManager–#ACTIVITY_SERVICE————————–Activity管理器
  • android.os.PowerManager–#POWER_SERVICE———————————电源管理
  • android.app.AlarmManager–#ALARM_SERVICE——————————–提醒管理
  • android.app.NotificationManager–#NOTIFICATION_SERVICE——————通知管理
  • android.app.KeyguardManager–#KEYGUARD_SERVICE————————–键盘管理
  • android.location.LocationManager–#LOCATION_SERVICE———————定位管理
  • android.app.SearchManager–#SEARCH_SERVICE——————————搜索管理
  • android.hardware.SensorManager–#SENSOR_SERVICE————————-传感器管理
  • android.os.storage.StorageManager–#STORAGE_SERVICE———————存储管理
  • android.os.Vibrator–#VIBRATOR_SERVICE———————————-震动管理
  • android.net.ConnectivityManager–#CONNECTIVITY_SERVICE——————网络管理
  • android.net.wifi.WifiManager–#WIFI_SERVICE—————————–Wifi管理
  • android.media.AudioManager–#AUDIO_SERVICE——————————音频管理
  • android.media.MediaRouter–#MEDIA_ROUTER_SERVICE————————媒体路由器
  • android.telephony.TelephonyManager–#TELEPHONY_SERVICE——————电话管理
  • android.telephony.SubscriptionManager–#TELEPHONY_SUBSCRIPTION_SERVICE–双卡信息管理
  • android.telephony.CarrierConfigManager–#CARRIER_CONFIG_SERVICE———电话配置信息管理
  • android.view.inputmethod.InputMethodManager–#INPUT_METHOD_SERVICE——输入法管理
  • android.app.UiModeManager–#UI_MODE_SERVICE—————————–UI模式管理
  • android.app.DownloadManager–#DOWNLOAD_SERVICE————————–下载管理
  • android.os.BatteryManager–#BATTERY_SERVICE—————————–电池管理
  • android.app.job.JobScheduler–#JOB_SCHEDULER_SERVICE——————–任务执行者
  • android.app.usage.NetworkStatsManager–#NETWORK_STATS_SERVICE———–网络状态管理
  • android.os.HardwarePropertiesManager–#HARDWARE_PROPERTIES_SERVICE——硬件属性管理

上面这些服务,你可以通过Context.getSystemService(Context.名称)直接获取,然后进行操作。

类图

首先看一下类图关系:

这里写图片描述

讲解:

1.ContextImpl、ContextWrapper与Context的关系

Context是一个静态类,ContextImpl和ContextWrapper都继承了Context,也就是都实现了Context的静态方法,但是,从代码中我们看到ContextImpl是Context静态方法的详细实现类,而ContextWrapper是调用了mBase对应的方法,而mBase是Context,从代码跟踪看mBase其实就是ContextImpl,因此ContextWrapper最终是调用ContextImpl中的实现方法。也就是说我们调用的Context中的任何方法都是在ContextImpl中处理的,因此我们在跟踪代码时只需要去ContextImpl中查看对应方法处理就好了。上面只是介绍,下面我们根据具体代码来分析一下到底怎么实现的。

从ContextWrapper代码中我们可以看到(不贴全部代码了),只有构造函数、attachBaseContext方法以及getBaseContext方法不是复写方法,其他方方法均为复写方法:

【ContextWrapper.java】

    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }

    /**
     * Set the base context for this ContextWrapper.  All calls will then be
     * delegated to the base context.  Throws
     * IllegalStateException if a base context has already been set.
     * 
     * @param base The new base context for this wrapper.
     */
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }

    /**
     * @return the base context as set by the constructor or setBaseContext
     */
    public Context getBaseContext() {
        return mBase;
    }

我们可以看到只有构造函数和attachBaseContext方法传入了mBase,那么从attachBaseContext方法中我们看到如果mBase存在又调用了该方法就会抛出异常,因此我们知道如果调用了该方法,那么构造函数不能传入这个值,我们看一下哪些地方调用了这个attachBaseContext方法,由代码可以看到Application、activity和service均调用了这个方法,首先我们来看Application中的代码:

【Application.java】

    /**
     * @hide
     */
    /* package */ final void attach(Context context) {
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }

Application中的attach方法中调用了attachBaseContext方法,参数context也是通过attach方法传入的,那么我们再跟踪这个attach方法:

是在Instrumentation类中调用的:

【Instrumentation.java】

    static public Application newApplication(Class<?> clazz, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = (Application)clazz.newInstance();
        app.attach(context);
        return app;
    }

上面方法调用地方是:

【Instrumentation.java】

    public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        return newApplication(cl.loadClass(className), context);
    }

从代码可以看到是在new Application时调用的,那么我们接着看哪里调用了这个方法:

【LoadedApk.java】

public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        ...

        try {
            ...
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
            ...
        }
        ...
        return app;
    }

上面方法是在LoadedApk类中调用的,我们先不分析这个类,后续我们会详细讲这个过程,我们先分析上面这段代码,我们看到这里面通过调用ContextImpl.createAppContext方法来创建ContextImpl,然后将参数传入newApplication方法,因此我们看到上面的mBase就是ContextImpl,那么还有Activity和Service.我们先分析Service,因为从关系图可以看到Service和Application都是直接继承ContextWrapper,而Activity则是继承ContextThemeWrapper,ContextThemeWrapper继承ContextWrapper。

【Service.java】

public final void attach(
            Context context,
            ActivityThread thread, String className, IBinder token,
            Application application, Object activityManager) {
        attachBaseContext(context);
        ...
    }

attachBaseContext方法是在Service中的attach方法中调用的,接着看attach方法的调用:

【ActivityThread.java】

private void handleCreateService(CreateServiceData data) {
        ...
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);

            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            service.onCreate();
         ...
    }

在这里我们看到传入的context就是ContextImpl,从而得到验证,下面我们还看到service.onCreate方法,我们看到了先调用attach方法然后调用onCreate方法。

最后我们看一下Activity,从上面关系图我们看到,Activity不是直接继承ContextWrapper,而是继承的ContextThemeWrapper,ContextThemeWrapper继承ContextWrapper。从名字我们可以看到ContextThemeWrapper包含主题的信息,其实不难理解,四大组件只有Activity是带界面的,其他都是没有界面的,因此Activity需要主题信息来显示不同的界面效果。在ContextThemeWrapper中我们看到复写了attachBaseContext方法,方法中只有一行代码就是调用父类的attachBaseContext方法。如下所示:

【ContextThemeWrapper.java】

    @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase);
    }

在Activity中只有一个方法中调用了该方法,看代码:

【Activity.java】

final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window) {
        attachBaseContext(context);

        ...
    }

我们接着追踪attach方法,看代码:

【ActivitThread.java】

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
       ...

            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);
                ...
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window);

                ...
            }
            ...
        return activity;
    }

方法performLaunchActivity其实是启动Activity的方法,这里我们暂时不讲,后续我们会详细讲解,我们先理清楚Context,从上面代码我们可以看到此处传入的Context是通过createBaseContextForActivity方法创建的,那么我们看一下这个方法:

【ActivitThread.java】

private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
        ...

        ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.token, displayId, r.overrideConfig);
        appContext.setOuterContext(activity);
        Context baseContext = appContext;

        ...
        return baseContext;
    }

从上面代码我肯可以清楚的看到baseContext是appContext赋值的,而appContext就是ContextImpl,因此Activity中的Context也是ContextImpl。到现在我们已经搞清楚了ContextImpl、Context、ContextWrapper、ContextThemeWrapper以及Application、Service和Activity的关系,那么以后看源码我们就知道与Context相关的实现方法都在ContextImpl类中,如果需要看详细实现过程只需要去ContextImpl类中找到相应方法开始跟踪即可。

从下一章我们开始讲解四大组件的启动过程。

首发地址:http://www.codemx.cn

Android开发群:192508518

微信公众账号:Code-MX

注:本文原创,转载请注明出处,多谢。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android系统代码情景分析》随书光盘内容(代码) 目录如下: 第1篇 初识Android系统 第1章 准备知识 1.1 Linux内核参考书籍 1.2 Android应用程序参考书籍 1.3 下载、编译和运行Android代码 1.3.1 下载Android代码 1.3.2 编译Android代码 1.3.3 运行Android模拟器 1.4 下载、编译和运行Android内核代码 1.4.1 下载Android内核代码 1.4.2 编译Android内核代码 1.4.3 运行Android模拟器 1.5 开发第一个Android应用程序 1.6 单独编译和打包Android应用程序模块 1.6.1 导入单独编译模块的mmm命令 1.6.2 单独编译Android应用程序模块 1.6.3 重新打包Android系统镜像文件 第2章 硬件抽象层 2.1 开发Android硬件驱动程序 2.1.1 实现内核驱动程序模块 2.1.2 修改内核Kconfig文件 2.1.3 修改内核Makefile文件 2.1.4 编译内核驱动程序模块 2.1.5 验证内核驱动程序模块 2.2 开发C可执行程序验证Android硬件驱动程序 2.3 开发Android硬件抽象层模块 2.3.1 硬件抽象层模块编写规范 2.3.2 编写硬件抽象层模块接口 2.3.3 硬件抽象层模块的加载过程 2.3.4 处理硬件设备访问权限问题 2.4 开发Android硬件访问服务 2.4.1 定义硬件访问服务接口 2.4.2 实现硬件访问服务 2.4.3 实现硬件访问服务的JNI方法 2.4.4 启动硬件访问服务 2.5 开发Android应用程序来使用硬件访问服务 第3章 智能指针 3.1 轻量级指针 3.1.1 实现原理分析 3.1.2 应用实例分析 3.2 强指针和弱指针 3.2.1 强指针的实现原理分析 3.2.2 弱指针的实现原理分析 3.2.3 应用实例分析 第2篇 Android专用驱动系统 第4章 Logger日志系统 4.1 Logger日志格式 4.2 Logger日志驱动程序 4.2.1 基础数据结构 4.2.2 日志设备的初始化过程 4.2.3 日志设备文件的打开过程 4.2.4 日志记录的读取过程 4.2.5 日志记录的写入过程 4.3 运行时库层日志库 4.4 C/C++日志写入接口 4.5 Java日志写入接口 4.6 Logcat工具分析 4.6.1 相关数据结构 4.6.2 初始化过程 4.6.3 日志记录的读取过程 4.6.4 日志记录的输出过程 第5章 Binder进程间通信系统 5.1 Binder驱动程序 5.1.1 基础数据结构 5.1.2 Binder设备的初始化过程 5.1.3 Binder设备文件的打开过程 5.1.4 Binder设备文件的内存映射过程 5.1.5 内核缓冲区管理 5.2 Binder进程间通信库 5.3 Binder进程间通信应用实例 5.4 Binder对象引用计数技术 5.4.1 Binder本地对象的生命周期 5.4.2 Binder实体对象的生命周期 5.4.3 Binder引用对象的生命周期 5.4.4 Binder代理对象的生命周期 5.5 Binder对象死亡通知机制 5.5.1 注册死亡接收通知 5.5.2 发送死亡接收通知 5.5.3 注销死亡接收通知 5.6 Service Manager的启动过程 5.6.1 打开和映射Binder设备文件 5.6.2 注册为Binder上下文管理者 5.6.3 循环等待Client进程请求 5.7 Service Manager代理对象的获取过程 5.8 Service组件的启动过程 5.8.1 注册Service组件 5.8.2 启动Binder线程池 5.9 Service代理对象的获取过程 5.10 Binder进程间通信机制的Java接口 5.10.1 Service Manager的Java代理对象的获取过程 5.10.2 Java服务接口的定义和解析 5.10.3 Java服务的启动过程 5.10.4 Java服务代理对象的获取过程 5.10.5 Java服务的调用过程 第6章 Ashmem匿名共享内存系统 6.1 Ashmem驱动程序 6.1.1 基础数据结构 6.1.2 匿名共享内存设备的初始化过程 6.1.3 匿名共享内存设备文件的打开过程 6.1.4 匿名共享内存设备文件的内存映射过程 6.1.5 匿名共享内存块的锁定和解锁过程 6.1.6 匿名共享内存块的回收过程 6.2 运行时库cutils的匿名共享内存访问接口 6.3 匿名共享内存的C++访问接口 6.3.1 MemoryHeapBase 6.3.2 MemoryBase 6.3.3 应用实例 6.4 匿名共享内存的Java访问接口 6.4.1 MemoryFile 6.4.2 应用实例 6.5 匿名共享内存的共享原理 第3篇 Android应用程序框架 第7章 Activity组件的启动过程 7.1 Activity组件应用实例 7.2 根Activity组件的启动过程 7.3 子Activity组件在进程内的启动过程 7.4 子Activity组件在新进程中的启动过程 第8章 Service组件的启动过程 8.1 Service组件应用实例 8.2 Service组件在新进程中的启动过程 8.3 Service组件在进程内的绑定过程 第9章 Android系统广播机制 9.1 广播机制应用实例 9.2 广播接收者的注册过程 9.3 广播的发送过程 第10章 Content Provider组件的实现原理 10.1 Content Provider组件应用实例 10.1.1 ArticlesProvider 10.1.2 Article 10.2 Content Provider组件的启动过程 10.3 Content Provider组件的数据共享原理 10.3.1 数据共享模型 10.3.2 数据传输过程 10.4 Content Provider组件的数据更新通知机制 10.4.1 注册内容观察者 10.4.2 发送数据更新通知 第11章 Zygote和System进程的启动过程 11.1 Zygote进程的启动脚本 11.2 Zygote进程的启动过程 11.3 System进程的启动过程 第12章 Android应用程序进程的启动过程 12.1 应用程序进程的创建过程 12.2 Binder线程池的启动过程 12.3 消息循环的创建过程 第13章 Android应用程序的消息处理机制 13.1 创建线程消息队列 13.2 线程消息循环过程 13.3 线程消息发送过程 13.4 线程消息处理过程 第14章 Android应用程序的键盘消息处理机制 14.1 键盘消息处理模型 14.2 InputManager的启动过程 14.2.1 创建InputManager 14.2.2 启动InputManager 14.2.3 启动InputDispatcher 14.2.4 启动InputReader 14.3 InputChannel的注册过程 14.3.1 创建InputChannel 14.3.2 注册Server端InputChannel 14.3.3 注册系统当前激活的应用程序窗口 14.3.4 注册Client端InputChannel 14.4 键盘消息的分发过程 14.4.1 InputReader获得键盘事件 14.4.2 InputDispatcher分发键盘事件 14.4.3 系统当前激活的应用程序窗口获得键盘消息 14.4.4 InputDispatcher获得键盘事件处理完成通知 14.5 InputChannel的注销过程 14.5.1 销毁应用程序窗口 14.5.2 注销Client端InputChannel 14.5.3 注销Server端InputChannel 第15章 Android应用程序线程的消息循环模型 15.1 应用程序主线程消息循环模型 15.2 与界面无关的应用程序子线程消息循环模型 15.3 与界面相关的应用程序子线程消息循环模型 第16章 Android应用程序的安装和显示过程 16.1 应用程序的安装过程 16.2 应用程序的显示过程

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值