首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Android系统服务(SystemService)简介

Android系统服务(SystemService)简介

作者头像
233333
发布于 2020-03-18 08:45:33
发布于 2020-03-18 08:45:33
2K00
代码可运行
举报
运行总次数:0
代码可运行

什么是SystemService

我们在Android开发过程中经常会用到各种各样的系统管理服务,如进行窗口相关的操作会用到窗口管理服务WindowManager,进行电源相关的操作会用到电源管理服务PowerManager,还有很多其他的系统管理服务,如通知管理服务NotifacationManager、振动管理服务Vibrator、电池管理服务BatteryManager…… 这些Manager提供了很多对系统层的控制接口。对于App开发者,只需要了解这些接口的使用方式就可以方便的进行系统控制,获得系统各个服务的信息,而不需要了解这些接口的具体实现方式。而对于Framework开发者,则需要了解这些Manager服务的常用实现模式,维护这些Manager的接口,扩展这些接口,或者实现新的Manager。

一个简单的SystemService

我们从一个简单的系统服务Vibrator服务来看一下一个系统服务是怎样建立的。

Vibrator服务提供的控制手机振动的接口,应用可以调用Vibrator的接口来让手机产生振动,达到提醒用户的目的。

从Android的官方文档中可以看到Vibrator只是一个抽象类,只有4个抽象接口:

  • bstract void cancel() 取消振动
  • abstract boolean hasVibrator() 是否有振动功能
  • abstract void vibrate(long[] pattern, int repeat) 按节奏重复振动
  • abstract void vibrate(long milliseconds) 持续振动

应用中使用振动服务的方法也很简单,如让手机持续振动500毫秒:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Vibrator mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
mVibrator.vibrate(500);

Vibrator使用起来很简单,我们再来看一下实现起来是不是也简单。

从文档中可以看到Vibrator只是定义在android.os 包里的一个抽象类,在源码里的位置即frameworks/base/core/java/android/os/Vibrator.java,那么应用中实际使用的是哪个实例呢?应用中使用的Vibrator实例是通过Context的一个方法getSystemService(Context.VIBRATOR_SERVICE)获得的,而Context的实现一般都在ContextImpl中,那我们就看一下ContextImpl是怎么实现getSystemService的:

frameworks/base/core/java/android/app/ContextImpl.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public Object getSystemService(String name) {
    return SystemServiceRegistry.getSystemService(this, name);
}

frameworks/base/core/java/android/app/SystemServiceRegistry.java (SystemServiceRegistry是 Android 6.0之后才有的,Android 6.0 之前的代码没有该类,下面的代码是直接写在ContextImpl里的)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 public static Object getSystemService(ContextImpl ctx, String name) {
    ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
    return fetcher != null ? fetcher.getService(ctx) : null;
}

SYSTEM_SERVICE_MAP是一个HashMap,通过我们服务的名字name字符串,从这个HashMap里取出一个ServiceFetcher,再return这个ServiceFetcher的getService()。ServiceFetcher是什么?它的getService()又是什么?既然他是从SYSTEM_SERVICE_MAP这个HashMap里get出来的,那就找一找这个HashMap都put了什么。

通过搜索SystemServiceRegistry可以找到如下代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private static <T> void registerService(String serviceName, Class<T> serviceClass,
        ServiceFetcher<T> serviceFetcher) {
    SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
    SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}

这里往SYSTEM_SERVICE_MAP里put了一对String与ServiceFetcher组成的key/value对,registerService()又是从哪里调用的?继续搜索可以发现很多类似下面的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class SystemVibrator extends Vibrator {
    ...
}

我们再从SystemVibrator看一下系统的振动控制是怎么实现的。以hasVibrator()为例,这个是查询当前系统是否能够振动,在SystemVibrator中它的实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public boolean hasVibrator() {
    ...
    try {
        return mService.hasVibrator();
    } catch (RemoteException e) {
    }
    ...
}

这里直接调用了一个mService.hasVibrator()。mService是什么?哪来的?搜索一下可以发现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private final IVibratorService mService;
public SystemVibrator() {
    ...
    mService = IVibratorService.Stub.asInterface(
            ServiceManager.getService("vibrator"));
}

mService 是一个IVibratorService,我们先不去管IVibratorService.Stub.asInterface是怎么回事,先看一下IVibratorService是什么。搜索一下代码发现这并不是一个java文件,而是一个aidl文件:

frameworks/base/core/java/android/os/IVibratorService.aidl

AIDL (Android Interface Definition Language) 是Android中的接口定义文件,为系统提供了一种简单跨进程通信方法。

IVibratorService 中定义了几个接口,SystemVibrator中使用的也是这几个接口,包括我们刚才使用的hasVibrator()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IVibratorService
{
    boolean hasVibrator();
    void vibrate(...);
    void vibratePattern(...);
    void cancelVibrate(IBinder token);
}

这里又只是接口定义,接口实现在哪呢?通过在frameworks/base目录下进行grep搜索,或者在AndroidXRef搜索,可以发现IVibratorService接口的实现在frameworks/base/services/java/com/android/server/VibratorService.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class VibratorService extends IVibratorService.Stub

可以看到 VibratorService实现了IVibratorService定义的所有接口,并通过JNI调用到native层,进行更底层的实现。更底层的实现不是这篇文档讨论的内容,我们需要分析的是VibratorService怎么成为系统服务的。那么VibratorService是怎么注册为系统服务的呢?在SystemServer里面:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
VibratorService vibrator = null;
...
//实例化VibratorService并添加到ServiceManager
traceBeginAndSlog("StartVibratorService");
vibrator = new VibratorService(context);
ServiceManager.addService("vibrator", vibrator);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
...
//通知服务系统启动完成
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeVibratorServiceReady");
try {
    vibrator.systemReady();
} catch (Throwable e) {
    reportWtf("making Vibrator Service ready", e);
}
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);

这样在SystemVibrator里就可以通过下面的代码连接到VibratorService,与底层的系统服务进行通信了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
IVibratorService.Stub.asInterface(ServiceManager.getService("vibrator"));

mService相当于IVibratorService在应用层的一个代理,所有的实现还是在SystemServer的VibratorService里。

看代码时可以发现registerService是在static代码块里静态调用的,所以getSystemServcr获得的各个Manager也都是单例的。

System Service实现流程

从上面的分析,我们可以总结出Vibrator服务的整个实现流程:

  1. 定义一个抽象类Vibrator,定义了应用中可以访问的一些抽象方法
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
frameworks/base/core/java/android/os/Vibrator.java
  1. 定义具体的类SystemVibrator继承Vibrator,实现抽象方法

frameworks/base/core/java/android/os/SystemVibrator.java

  1. 定义一个AIDL接口文件IVibratorService,定义系统服务接口

frameworks/base/core/java/android/os/IVibratorService.aidl

  1. 定义服务VibratorService,实现IVibratorService定义的接口

frameworks/base/services/java/com/android/server/VibratorService.java

  1. 将VibratorServicey添加到系统服务

frameworks/base/services/java/com/android/server/SystemServer.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
VibratorService vibrator = null;
...
//实例化VibratorService并添加到ServiceManager
Slog.i(TAG, "Vibrator Service");
vibrator = new VibratorService(context);
ServiceManager.addService("vibrator", vibrator);
...
//通知服务系统启动完成
try {
    vibrator.systemReady();
} catch (Throwable e) {
    reportWtf("making Vibrator Service ready", e);
}
  1. 在SystemVibrator中通过IVibratorService的代理连接到VibratorService,这样SystemVibrator的接口实现里就可以调用IVibratorService的接口:

frameworks/base/core/java/android/os/SystemVibrator.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private final IVibratorService mService;
...
public SystemVibrator() {
    ...
    mService = IVibratorService.Stub.asInterface(
            ServiceManager.getService("vibrator"));
    ...
    public boolean hasVibrator() {
        ...
        try {
            return mService.hasVibrator();
        } catch (RemoteException e) {
        }
        ...
    }
}
  1. 在Context里定义一个代表Vibrator服务的字符串

frameworks/base/core/java/android/content/Context.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static final String VIBRATOR_SERVICE = "vibrator";
  1. 在ContextImpl里添加SystemVibrator的实例化过程

frameworks/base/core/java/android/app/ContextImpl.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
    return new SystemVibrator(ctx);
}});  
  1. 在应用中使用Vibrator的接口
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Vibrator mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
mVibrator.vibrate(500);
  1. 为保证编译正常,还需要将AIDL文件添加到编译配置里

frameworks/base/Android.mk

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
LOCAL_SRC_FILES += \
...
core/java/android/os/IVibratorService.aidl \

System Service 新加接口

如果我们需要实现一个新的系统服务,就可以按照上面的步骤在系统中扩展出一个新的服务,并给应用层提供出使用接口。如果想在Vibrator里添加一个新的接口,需要下面3步:

  1. 在IVibratorService添加接口;
  2. 在VibratorService添加接口的实现;
  3. 在Vibrator及SystemVibrator里扩展新的接口;

这样应用中就可以使用Vibrator的新接口了。

应用层与 System Service 通信

上面的实现我们看到的只是从应用层通过服务代理,调用系统服务的接口,如果我们想反过来,将系统服务的状态通知给应用层,该怎么做呢?

  • 方法一:使用Broadcast

我们知道使用Broadcast广播可以实现跨进程的消息传递,一些系统服务也使用了这种方法。如电池管理服务BatteryManagerService,收到底层上报的电池状态变化信息时,就将当前的电池状态封装在一个Intent里,action为android.intent.action.BATTERY_CHANGED。应用只要注册一个对应的BroadcastReceiver就可以收到BatterManagerService发送的电池状态信息。

  • 方法二:使用AIDL

从上面我们可以知道,通过AIDL定义一套接口,由系统服务端实现这些接口,应用端使用一个相应的代理就可以访问系统服务的接口,那反过来让应用端实现AIDL接口,系统服务端使用代理调用应用端的接口可不可以呢?答案是YES。那么接下来的问题是怎么让系统服务得到这个代理。我们再来看一个LocationManager的例子。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//获得定位服务
LocationManager locationManager = 
        (LocationManager) getSystemService(Context.LOCATION_SERVICE);

//定义定位监听器
LocationListener locationListener = new LocationListener() {
    public void onLocationChanged(Location location) {
        //监听到位置信息
    }
    ...
};

//注册监听器
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 
        0, 0, locationListener);

从上面的代码可以看到,我们创建了一个位置监听器LocationListener,并将这个监听器在LocationManager里进行了注册。当系统定位到系统的位置后,就会回调监听器的onLocationChanged(),将位置信息通知给监听器。LocationListener就是一个系统服务调用应用层接口的例子,我们就研究一下LocationListener的实现方式。

我们先从LocationManager怎么注册LocationListener开始研究: frameworks/base/location/java/android/location/LocationManager.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private final ILocationManager mService;
...
private void requestLocationUpdates(LocationRequest request, 
        LocationListener listener, Looper looper, PendingIntent intent) {
    ...
    // wrap the listener class
    ListenerTransport transport = wrapListener(listener, looper);
    try {
        mService.requestLocationUpdates(request, transport, 
                intent, packageName);
   } catch (RemoteException e) {
       Log.e(TAG, "RemoteException", e);
   }
}

可以看到LocationListener被重新封装成了一个ListenerTransport,然后传递给了ILocationManager ,从前面的分析可以猜测到这个ILocationManager应该就是LocationManagerService的一个代理。那么ListenerTransport又是什么呢?搜索LocationManager.java可以找到:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private class ListenerTransport extends ILocationListener.Stub {
    ...
    @Override
    public void onLocationChanged(Location location) {
        ...
    }
}

原来是ILocationListener.Stub的一个继承实现,那么ILocationListener应该就是一个AIDL接口定义: frameworks/base/location/java/android/location/ILocationListener.aidl

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
oneway interface ILocationListener
{
    void onLocationChanged(in Location location);
    ...
}

而在LocationManagerService里只要调用ILocationListener的方法就可以将消息传递给应用层的监听:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mListener.onLocationChanged(new Location(location));

实现 System Service 的注意事项

  1. 注意防止阻塞 应用层访问系统服务提供的接口时会有两种情况:

一种是应用调用端需要等待服务实现端处理完成,返回处理结果,这样如果服务端发生阻塞,那么应用端也会发生阻塞,因此在实现服务端的实现时要注意不要发生阻塞。

另一种是调用端不需要等待服务端返回结果,调用完成后直接返回void,这样服务端发生阻塞不会影响到应用端,这样的单向的接口在AIDL里定义时需要添加oneway关键字,如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
oneway void statusBarVisibilityChanged(int visibility);

对于需要在服务端调用,在应用端实现的接口,考虑到系统的稳定性以及安全性,一般都会设计成上面的第二种,即AIDL里所有的接口都是单向的,如上面的ILocationListener

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
oneway interface ILocationListener
  1. 注意多线程访问

每个系统服务在系统进程中只有一个实例,而且应用中系统服务的代理也是单例的,而且应用端的访问,在系统进程都是使用独立的线程进行响应,所以访问同一个系统服务的接口时必然会出现多个线程或者多个进程同时访问的情况。为保证系统服务的线程安全,需要对系统服务的进程进行多线程访问的保护,目前主要有两种实现线程安全的方法:

一种是通过同步锁机制,锁住一个对象实例(一般是这个服务对象本身),这样这个服务同一时间只能响应一个访问请求,如LocationManagerService里:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public boolean callStatusChangedLocked(...) {
    ...
    synchronized (this) {
    ...
    }
}

另一种方法就是使用Handler机制,这种服务一般会创建一个单独的线程,当有应用端访问请求到来时会向服务线程的Handler里发送一个Message,利用单线程顺序执行的特性,保证所有的访问都按顺序进行处理,但这种方法只适合单向的访问,不适合需要返回的双向访问。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-03-08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
软件绘制 & 硬件加速绘制 【DisplayList & RenderNode】
两者都是从SF获取一块内存,绘制都是在APP端,绘制好后都是通知SF去进行合成图层
北洋
2023/09/18
7140
理解Android硬件加速原理的小白文
硬件加速,直观上说就是依赖GPU实现图形绘制加速,软硬件加速的区别主要是图形的绘制究竟是GPU来处理还是CPU,如果是GPU,就认为是硬件加速绘制,反之,软件绘制。在Android中也是如此,不过相对于普通的软件绘制,硬件加速还做了其他方面优化,不仅仅限定在绘制方面,绘制之前,在如何构建绘制区域上,硬件加速也做出了很大优化,因此硬件加速特性可以从下面两部分来分析:
看书的小蜗牛
2018/06/29
2K0
理解Android硬件加速原理的小白文
从零开始仿写一个抖音App——Android绘制机制以及Surface家族源码全解析
本文首发于微信公众号——世界上有意思的事,搬运转载请注明出处,否则将追究版权责任。微信号:a1018998632,交流qq群:859640274
何时夕
2019/03/04
3.2K0
从零开始仿写一个抖音App——Android绘制机制以及Surface家族源码全解析
硬件渲染源码分析流程详解
硬件渲染中采用AttachInfo的mThreadRenderer.draw方法传入view,attachinfo和ViewRootImpl开始硬件渲染。
小柔
2022/10/09
1.3K0
Android硬件加速(二)-RenderThread与OpenGL GPU渲染
Android4.0之后,系统默认开启硬件加速来渲染视图,之前,理解Android硬件加速的小白文简单的讲述了硬件加速的简单模型,不过主要针对前半阶段,并没怎么说是如何使用OpenGL、GPU处理数据的,OpenGL主要处理的任务有Surface的composition及图形图像的渲染,本篇文章简单说一下后半部分的模型,这部分对于理解View渲染也有不少帮助,也能更好的帮助理解GPU渲染玄学曲线。
看书的小蜗牛
2018/08/16
10.7K0
Android硬件加速(二)-RenderThread与OpenGL GPU渲染
硬件加速:RenderThread处理DrawOp树
接收SF上抛的Vsync信号,通过监听DisplayEventReceiver的BitTube来回调编舞者的doFrame方法
小柔
2022/10/09
6900
硬件加速:RenderThread处理DrawOp树
Android硬件加速介绍与实现
概述 在手机客户端尤其是Android应用的开发过程中,我们经常会接触到“硬件加速”这个词。由于操作系统对底层软硬件封装非常完善,上层软件开发者往往对硬件加速的底层原理了解很少,也不清楚了解底层原理的意义,因此常会有一些误解,如硬件加速是不是通过特殊算法实现页面渲染加速,或是通过硬件提高CPU/GPU运算速率实现渲染加速。 本文尝试从底层硬件原理,一直到上层代码实现,对硬件加速技术进行简单介绍,其中上层实现基于Android 6.0。 硬件加速对App开发的意义 对于App开发者,简单了解硬件加速原理及上层
xiangzhihong
2018/01/26
1.6K0
Android硬件加速原理和简介
原理:使用PNG图片(BitmaoDrable)解码PNG图片生成Bitmap,传到底层,有GPU渲染图片解码,消耗CPU运算资源,Bitmap占内存大,绘制慢。
Demo_Yang
2018/10/15
1.6K0
Vsync信号和View绘制流程的关系
vsync可以由底层HardWare提供经由Display发送,当底层Hardware不能提供时也会发送vsync信号到Display。vsync屏蔽了底层Hal,使得没有Vsync的硬件也可以使用。
北洋
2022/05/06
4280
硬件加速绘制基础知识
OPENGL 是统一不同厂商GPU绘制的接口,通过GPU的计算得到一张图片(内存中的一块Buffer保存着信息)
小柔
2022/10/09
6640
hwui介绍与分析
hwui全称**HardwareAcceleratedRenderingEngineforUI,**hwui是一个基于GPU加速的2D图形引擎。HWUI的目标是提供高效、稳定、高质量的2D图形渲染能力,为Android系统的UI体验提供技术支持。
用户1907613
2023/09/17
2.5K0
hwui介绍与分析
【Android UI】Canvas 画布 ⑥ ( Canvas 绘图源码分析 | ViewRootImpl#draw 方法源码 | ViewRootImpl#drawSoftware 方法源码 )
Canvas 状态保存机制 中 , 存在两个栈结构 , 分别是 状态栈 和 图层栈 ;
韩曙亮
2023/03/30
6150
[030]王小二图解Android-UI绘制篇【文字版】
本文只是视频王小二图解Android【007】UI绘制篇的提纲和整理,建议配合视频学习
王小二
2020/06/08
1.2K0
[030]王小二图解Android-UI绘制篇【文字版】
软件绘制源码流程分析
lock方法中 首先声明NativeWindowBuffer对象,然后调用dequeBuffe获取到ANativeWindwoBuffer对象接着请求SF真正创建GraphBuffer对象并返回NativeWindowBuffer
小柔
2022/10/09
5110
View的绘制-draw流程详解
根据 measure 测量出的宽高,layout 布局的位置,渲染整个 View 树,将界面呈现出来。
用户5546570
2019/06/06
1.4K0
View的绘制-draw流程详解
使用 GPU 渲染模式分析工具进行分析
其实就是处理输入事件开始到结束的时间,如果竖条中此颜色高度过高代表输入事件应放到其他线程去做
小柔
2022/10/09
1.4K0
使用 GPU 渲染模式分析工具进行分析
Android 绘制原理浅析【干货】
对于Android开发,在面试的时候,经常会被问到,说一说View的绘制流程?我也经常问面试者,View的绘制流程.
Rouse
2019/08/06
1.5K1
SurfaceView 与 TextureView 详解
Surface 就是“表面”的意思,可以简单理解为内存中的一段绘图缓冲区。在SDK的文档中,对Surface的描述是这样的:“Handle onto a raw buffer that is being managed by the screen compositor”,翻译成中文就是“由屏幕显示内容合成器(screen compositor)所管理的原生缓冲器的句柄”, 这句话包括下面两个意思:
字节流动
2021/01/12
14.2K0
Android 图形架构之一 ——概述
本系列的文章,可以让你明白,一个View最终是如何显示到屏幕上的,从应用层到硬件抽象层。对分析app的卡顿,掉帧等 有很大帮助。
音视频开发进阶
2022/10/31
2.3K0
Android窗口管理分析(4):Android View绘制内存的分配、传递、使用
前文Android匿名共享内存(Ashmem)原理分析了匿名共享内存,它最主要的作用就是View视图绘制,Android视图是按照一帧一帧显示到屏幕的,而每一帧都会占用一定的存储空间,通过Ashmem机制APP与SurfaceFlinger共享绘图数据,提高图形处理性能,本文就看Android是怎么利用Ashmem分配及绘制的:
看书的小蜗牛
2018/06/29
2.5K0
推荐阅读
相关推荐
软件绘制 & 硬件加速绘制 【DisplayList & RenderNode】
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档