Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Android系统服务(SystemService)简介

Android系统服务(SystemService)简介

作者头像
233333
发布于 2020-03-18 08:45:33
发布于 2020-03-18 08:45:33
1.9K00
代码可运行
举报
运行总次数: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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Android插件化原理解析——Hook机制之Binder Hook
Android系统通过Binder机制给应用程序提供了一系列的系统服务,诸如ActivityManagerService,ClipboardManager, AudioManager等;这些广泛存在系统服务给应用程序提供了诸如任务管理,音频,视频等异常强大的功能。
weishu
2018/09/05
1.9K0
Activity启动过程
Activity作为Android四大组件中使用最频繁的组件,也是和用户交互最多的组件,可见它在Android技术体系的核心地位,了解Activity的启动过程可以帮助我们更好的了解Android系统和使用Activity。
八归少年
2024/03/11
3420
Android Hook 机制之简单实战
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/details/81459830
程序员徐公
2018/09/17
3.1K0
Android Hook 机制之简单实战
Android新增LED设备--从底层到上层理解安卓架构
为了更好的理解安卓的层次关系,本文在RK3399的安卓系统上增加LED灯的外设,并使用APP打开关闭LED灯。以这样一个最简单的实例,来演示从上层到底层的调用过程。首先从最底层的kernel层开始。
Jasonangel
2021/08/26
2.9K0
Android新增LED设备--从底层到上层理解安卓架构
图解 | 一图摸清Android系统服务
在日常开发中,可以通过Context.getSystemService()在自己的应用程序里获取到系统服务:
Holiday
2020/10/29
8030
图解 | 一图摸清Android系统服务
[Android][Framework] 添加系统服务
做系统开发,有时候需要自己定义一些接口供App使用, 同时为了方便维护管理,就会需要自己建立一个服务,把新的功能集中在一起。下面就是新建一个系统服务的基本步骤。
wOw
2020/01/20
1.1K0
[Android][Framework] 添加系统服务
做系统开发,有时候需要自己定义一些接口供App使用, 同时为了方便维护管理,就会需要自己建立一个服务,把新的功能集中在一起。下面就是新建一个系统服务的基本步骤。
wOw
2018/09/15
1.5K0
如何实现一个 System Services?
《Android 系统开发做什么?》写到 Android System Services 是专注于特定功能的模块化组件,应用框架 API 所提供的功能可与系统服务通信,以访问底层硬件。Android System Services 是如何写的?来以DisplayManagerService 为例,具体来看看。
吴小龙同學
2021/12/20
1.2K0
如何实现一个 System Services?
Android应用启动过程详解
当用户在启动器上点击应用图标时,启动器会发起启动请求。这通常通过调用startActivity()方法实现,该方法的参数包括一个Intent对象,表示要启动的Activity。此时,启动器会将启动请求传递给系统的ActivityManagerService(AMS)进行处理。
陆业聪
2024/07/23
3500
Android应用启动过程详解
Android系统启动——6 SystemServer启动
SystemServer是Android系统的核心之一,大部分Android提供的服务都运行在这个进程里,SystemServer中运行的服务总共有60多种。为了防止应用进程对系统造成破坏,Android的应用进程没有权限直接访问设备的底层资源,只能通过SystemService中的代理访问。通过Binder,用户进程在使用SystemService中的服务并没有太多不便变之处。
隔壁老李头
2018/08/30
3.4K2
Android系统启动——6 SystemServer启动
Android系统之System Server大纲
System Server是android 基本服务的提供者,是android系统运行的最基本需求,所有server运行在一个叫system_process的进程中,system_process进程是android java虚拟机跑的第一个进程,从Zygote 创建而来,是andorid系统最重要的java虚拟机。可以说,整个android系统的业务都是围绕system server而展开,所以,当system_process死掉了,手机必须重启。
233333
2024/07/02
2610
Android系统服务(一)解析ActivityManagerService(AMS)
相关文章 Android系统启动流程系列 Android应用进程系列 Android深入四大组件系列 前言 1.概述 AMS是系统的引导服务,应用进程的启动、切换和调度、四大组件的启动和管理都需要AMS的支持。从这里可以看出AMS的功能会十分的繁多,当然它并不是一个类承担这个重责,它有一些关联类,这在文章后面会讲到。AMS的涉及的知识点非常多,这篇文章主要会讲解AMS的以下几个知识点: AMS的启动流程。 AMS与进程启动。 AMS家族。 2.AMS的启动流程 AMS的启动是在SyetemServer进程
用户1269200
2018/02/01
1.9K0
Android系统服务(一)解析ActivityManagerService(AMS)
浅入浅出 Android 安全:第四章 Android 框架层安全
如我们在第1.2节中所描述的那样,应用程序框架级别上的安全性由 IPC 引用监视器实现。 在 4.1 节中,我们以 Android 中使用的进程间通信系统的描述开始,讲解这个级别上的安全机制。 之后,我们在 4.2 节中引入权限,而在 4.3 节中,我们描述了在此级别上实现的权限实施系统。
ApacheCN_飞龙
2022/12/01
5200
Android12 应用启动流程分析
最近因为一些需求,需要梳理 Android 应用的启动链路,从中寻找一些稳定的锚点来实现一些特殊的功能。本文即为对应用端启动全过程的一次代码分析记录。
evilpan
2023/02/12
1.4K0
Android12 应用启动流程分析
Android APP启动流程
startActivityForResult方法通过mInstrumentation对象调用execStartActivity,Instrumentation主要用来监控应用程序和系统的交互。mMainThread其实是一个ActivityThread对象,实际上就是Launcher这个应用的ActivityThread,在Launcher启动时初始化。
ruochen
2021/12/15
3.5K0
Android中Context用法详解学习
Android中Context用法详解学习 本文我们一起来探讨一下关于Android中Context的作用以及Context的详细用法,这对我们学习Android的资源访问有很大的帮助,文章中也贴出
用户1289394
2018/02/26
1.4K0
Android中Context用法详解学习
Android系统启动流程(三)解析SyetemServer进程启动过程
前言 上一篇我们学习了Zygote进程,并且知道Zygote进程启动了SyetemServer进程,那么这一篇我们就来学习Android7.0版本的SyetemServer进程的启动过程。 1.Zygote启动SyetemServer进程 在上一篇文章中我们讲到在ZygoteInit.java的startSystemServer函数中启动了SyetemServer进程,如下所示。 frameworks/base/core/java/com/android/internal/os/ZygoteInit.jav
用户1269200
2018/02/01
1.2K0
Android系统启动流程(三)解析SyetemServer进程启动过程
Android 安全之框架层安全(四)
继续Android安全系列之介绍,继续学习框架安全!本系列内容比较多,需要一步步的跟进。上期学习了android 用户空间层安全介绍,下篇继续介绍android framwork层安全。
开发者技术前线
2020/11/23
1.1K0
Android 安全之框架层安全(四)
相关推荐
Android插件化原理解析——Hook机制之Binder Hook
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文