Client/Server架构,也就是大家最常听到的C/S架构在后端开发中可以说是祖师爷级别的概念了。其实安卓的系统服务的设计也是遵循C/S架构的,甚至和最近很流行的微服务micro service架构也有关联。
今天我想用通俗一点的语言稍微讲解一下安卓端的CS架构,每个组件设计的理念,让大家更清晰的理解一下安卓的客户端和服务器到底是个什么东西。
简单的说,安卓的APP应用层可以当做是安卓C/S架构中的客户端。而安卓系统中,运行在系统进程system process的系统服务system service,被认为是服务器端。
客户端除了app本身之外,还包括安卓SDK的客户端公有API (public API)。基本上sdk里面带Manager字样的类,与之相对应的都会有一个安卓服务器端的实现。我们先抛开实现细节,教教大家怎么寻找客户端对应的服务器实现。
比如可以让app在运行时获取用户手机SIM卡等相关信息的TelephonyManager,大家可以看到它的其中和一个方法,用来获取手机当前的位置的方法。
public CellLocation getCellLocation() {
try {
Bundle bundle = getITelephony().getCellLocation();
return CellLocation.newFromBundle(bundle);
}
catch (RemoteException ex) {
return null;
}
它的调用了getITelehony()来获取一个ITelephony对象,大家一看这种带I开头的类就知道肯定要涉及IPC,跨进程调用了,它的服务器实现必然会继承ITelephony类的Stub。
所以在搜索该Manager的服务器端的实现的时候,直接搜索extends ITelephony的类就好。
public class PhoneInterfaceManager extends ITelephony.Stub {
@Override public CellIdentity getCellLocation(String callingPackage, String callingFeatureId) {
.....
}
}
果不其然,整个framework就只有PhoneInterfaceManager 继承了该ITelephony类的Stub,并且也可以找打之前getCellLocation 的具体实现。
当然其他的各种manager也是照着这样的方式一一实现的。整个安卓的客户端public API都有与之对应的实现,都是实现以I开头的Stub类。
这个小节我先简单的教大家怎么找到manager类的对应服务器端的实现,至于安卓是具体怎么实现这样的一对一映射我们接下来的小节再详细说明。
大家都知道编译一个安卓app需要android sdk,但是不少人没搞明白这个SDK到底是编译时用的还是运行时用的。
解答这个问题其实很简单,大家打开你的android studio,随便点击一个manager类的源码,就可以看出来。
很明显,这些SDK里面的类都不会最终打包进app的APK文件里面,如果真的用了这些类当做实现,运行时肯定都会crash(毕竟这里面全都是抛RuntimeException)。
所以SDK的类,都是没有具体实现的,我们把它们叫Stub类。他们只是用来帮助我们进行编译而已,目的是让app开发者能成功打包编译出APK。这个和gradle里面的compileOnly 关键字很像。而且这样设计也很有道理,毕竟如果每个app都需要把android framework的公有api类都打包进APK,那每个app安装文件都将变得巨大无比。
dependencies {
compileOnly 'javax.servlet:servlet-api:2.5'
}
但是在之前的图里,我明明还是把Manager类画在了APP的进程里面,也就是说运行时我们还是需要Manager类的。那这些类到底从哪来的呢?
关于Zygote的细节我们就不聊那么多,网上资源挺多的。但是我们需要知道的重点就是,每一个APP都是Zygote复制出来的一个进程(具体的实现应该是linux里面的fork),这个进程Dalvik(或者是ART)都是一个独立的虚拟机,virtual machine。在最原始的进程里面,所有的public API, 也就是那些客户端的Manager类都已经被加载进该进程(虚拟机)了。所以当每个app被启动的时候,启动APP的dalvik或者ART已经加载过了所有的客户端API的类。这样,app在运行时就不会找不到对应的Manager类 (symbol not found),但是同时通过android的stub sdk又减少了apk大小,可以说是一举两得。
https://man7.org/linux/man-pages/man2/fork.2.html
最后关于客户端再分享一个小知识,就是关于隐藏API。安卓的很多public manager class会有自己的隐藏api,可以看源码有没有带@hide的字样。比如AudioManager的getMasterStreamType方法,注释里面就加了hide。
/** *
Get the stream type whose volume is driving the UI sounds volume.
UI sounds are screen lock/unlock, camera shutter, key clicks...
@hide
*/
public int getMasterStreamType() {
}
加了这个注释之后,安卓在编译Stub sdk 的时候,就会把带这个注释的方法从stub类里面删掉,这样导致app开发者在编译阶段找不到该方法,从而达到隐藏的效果。大家通过android studio打开AudioManager的stub 就可以发现。
所以该隐藏也只是编译阶段隐藏而已,并没有做到真正的运行时隐藏。
也正因为该隐藏方式是在客户端的编译阶段隐藏,而且在运行时的dalvik和art虚拟机里面还是有对应类被加载,所以在运行时App还是可以通过java的反射来进行访问。。。。安全性并没有那么高。
有一些安全性要求比较高的API,会强制在服务器端run time检查调用者的进程ID,严格控制调用者身份。比如ActivityManager里面的一个方法,会检查callingUId。
void enforceShellRestriction(String restriction, int userHandle)
{
if (Binder.getCallingUid() == Process.SHELL_UID)
{ if (userHandle < 0 || mUserManager.hasUserRestriction(restriction, userHandle))
{ throw new SecurityException("Shell does not have permission to access user " + userHandle);
}
} }
这个思想其实和真正的后端开发就很相似了,你想在客户端做安全性验证,怎么也会出现漏洞。比如游戏客户端可以用很多种方式绕过安全检查,或者甚至修改游戏端运行时代码等等方式作弊。
说了这么多客户端的实现。是时候聊聊服务器端的实现了。服务器端的具体实现,我推荐大家看看这篇文章 如何实现一个 System Services?,这是博主吴小龙写的,步骤非常详细,大家可以先过一遍有个印象。
https://juejin.cn/post/6961760668705882142
不过再多的细节,服务器端的实现绕不过这三个概念:1. AIDL 2. Bound Service 3. ServiceManager and SystemService
大部分朋友应该对AIDL怎么用已经很了解了,这次我就不讲具体怎么用,而是应该怎么理解AIDL的设计初衷。
其实我们站在开发者的角度就可以很容易理解。当我的APP需要进行跨进程通信, 我作为开发者肯定希望有一个方便的客户端API,可以直接调用该API就间接的和system process通信.而不需要写一些非常复杂的C++的代码,比如我们总不能要求app开发者写jni文件去调用linux的系统调用来做这个事情。
站在服务器,也就是系统开发者的角度,我肯定希望当客户端调用我的某一个方法的时候,我不需要做额外的数据的序列化和反序列化。或者通俗一点说,就是客户端的调用的API的方法名,和我服务器端的方法名一致,接口长的样子要一样。比如在客户端TelephonyManager#isEmergencyNumber调用了ITelephony#isEmergencyNumber, 那么服务器端我也希望被调用服务器端实现的isEmergencyNumber方法。
AIDL机制就很好的解决了这个问题。AIDL可以帮助客户端和系统服务端开发者自动生成代码,包装了一些真正的跨进程通信的实现,让开发者不需要自己写linux的系统调用,同时还可以保持双方接口的一致(方法名一样等等)。
所以这一套设计方案说到底,就是为了开发者,尤其是app开发者更方便的开发而已。它的出现让跨进程变得更方便,但是这个跨进程也是在现有框架下进行,比如,客户端app开发要想和系统进行通信,必须通过系统现有的service与manager API进行通信,也还是有一定的限制。
实现了一个系统级别的服务,总得先生成该服务的实例,并且保存在某处(确保不会被垃圾回收),才能保证客户端能正常的调用。
安卓的ServiceManager就提供了这样的功能。
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static void addService(String name, IBinder service, boolean allowIsolated, int dumpPriority)
{
try {
getIServiceManager().addService(name, service, allowIsolated, dumpPriority);
}
catch (RemoteException e) { Log.e(TAG, "error in addService", e); }
}
这个方法最后会调用一个C++的底层代码,把服务实例注册。当前端的Manager api调用ServiceStub的方法的时候,安卓系统会通过IPC调用这些注册了的Service实例。
服务器端的服务可以以Service的的形式存在,也可以以SystemService的形式存在。Service就不用多说了,大家都知道怎么做bind service。
SystemService就不太一样了,大家可以看看这个类是个啥。
@SystemApi(client = Client.SYSTEM_SERVER)
public abstract class SystemService {
public void onBootPhase(@BootPhase int phase) {}
}
这个抽象类并不以Service的形式存在,而是一个简单的类。它唯一不一样的是提供了很多和启动周期相关的回调(boot phase).很多朋友不太懂什么是启动周期,其实很好理解,通俗一点就是,安卓设备被设置了屏幕锁之后,设备启动之后会被分成不同的启动阶段。
比如设备启动但是没有解锁是一个阶段,设备被解锁之后是另一个阶段。每个阶段开始之后,安卓的system server会启动不同的进程。最明显的例子是打电话的进程,设备在没有解锁之前也需要能接收或者拨打紧急电话。
SystemService类暴露了这样一个回调就用意很明显了,这样可以让不同的系统服务在不同的启动阶段做不同的事情。
比如安卓监控设备温度的系统服务,他只有在ActivityManager被加载之后才进行一系列业务逻辑的执行。
class ThermalManagerService extends SystemService {
@Override public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
onActivityManagerReady();
}
}
}
那么有了这么多服务,在哪里开始执行呢。就在SystemServer里面。
https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/power/ThermalManagerService.java;drc=b0193ccac5b8399f9b5ef270d102b5a50f9446ab;l=72
SystemServer.java的核心代码在这几行:
try {
t.traceBegin("StartServices");
startBootstrapServices(t);
startCoreServices(t);
startOtherServices(t);
startApexServices(t);
}
BootStrap service就是指我们上一节说到的SystemService,这些对象和bootstrap也就是启动周期紧密的相关,所以都是SystemService。Core Service就是系统需要的但是对bootstrap不敏感的服务。但是无论是哪种service最后都毫无例外的将自己注册在ServiceManager了。
ServiceManager.addService("sec_key_att_app_id_provider", new KeyAttestationApplicationIdProviderService(context));
就这样,安卓系统成功的创建了所有需要的服务的实例,并且将其注册了起来。到此为止,客户端已经可以尝试通过Manager API对这些系统服务进行IPC通信了。而且所有的这些Service的实例都被保存在一个List里面。
class SystemServiceManager {
private List<SystemService> mServices;
}
所以并不用担心这些Service被垃圾回收。到这里基本上安卓的前端和后端我们就都了解了。但是这些都只是一些概念的皮毛,有很多细节还没覆盖到。大家有兴趣可以再多查查资料。不过,安卓在架构上也在不断的进化。一个例子:很多后端的开发概念,微服务现在在安卓的架构中也开始被支持了。
从安卓10开始,android 的系统开发者已经开始尝试把很多framework中的代码模块化。从framework/base移动到packages/modules/下面,变成独立的模块,从而将该模块编译成独立的APEX文件(一个类似APK的安装文件)。
最显著的就是蓝牙模块:
https://cs.android.com/android/platform/superproject/+/master:packages/modules/Bluetooth/
这个模块编译之后是一个类似APK的APEX文件,这样的好处是:
蓝牙模块可以自己单独的通过google playstore更新了!!!!
也就是说,以后安卓的某一个模块出了新的fix,用户不需要再下载完整庞大的img了,安卓只需要通过playstore下载对应的APEX文件实现更新!
APEX文件的具体格式可以看这:
https://source.android.com/docs/core/ota/apex
可以说,安卓在C/S的架构上的进化从来没停止过。系统开发者的学习脚步也不能停啊。。。
本文由哈喽比特于1年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/Lyj9eZcC9fKJjJKiE4bB3A
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。