Android碎片化与兼容性问题的元凶
Android碎片化是其发展中的一个计划内的必然结果,也从来就不是什么问题。真正的问题是不同Android系统的应用兼容性。
Android的碎片化
Android的碎片化,是指它在发展的过程中,随着自身版本的更迭,以及硬件厂商的自行定制,而带来的一个版本数量爆炸的问题。
碎片化的Android本来Google的Android自身就有版本更迭的需求,这是当代大多数主流软件的做法。流行的Android版本有2.2、2.3、3.2、4.0.3、4.2.2、4.4、5.0、5.1等,近期6.0也发布了。
但是,和大多数软件不同的是,Android是手机的操作系统,不是说更新就更新的。很多改动不能保证系统层面的向前兼容,因此不能像普通软件那样推送了就更新。Android更新既有风险,也有限制。
例如,Android 4.0.3一共就100M,而Android 5.1.1有700M,这还仅仅是原生ROM的大小,厂商定制的往往更大一些。 对部分高端的Android 4.0时代的手机来说,也许仅仅需要更改System分区的大小。但是磁盘分区,通用做法是先格式化——所以有数据丢失的风险。而对部分低端的手机来说,根本就没那么大的容量来装系统,谁知道它会暴涨7倍——所以还有根本更新不了的限制情况。
这一点,Android类似Windows。
但是,这也就是一个线性增长而已。真正的麻烦来自于每一个厂商都自己做Android与手机硬件的适配,其中大的那些还做定制,例如小米的MIUI、华为的EMUI、联想的VIBEUI等。这就是N个厂商乘以M个版本,导致的版本数量爆炸。
开放手机联盟与Android的哲学
开放手机联盟的历史
每一本写Android相关的书,第一章提到发展历史时,都会提到一个开放手机联盟( Open Handset Alliance )。算上初创和后来加入的,从2007年至2015年,已有84个成员。
The OHA was established on 5 November 2007, led by Google with 34 members, including mobile handset makers, application developers, some mobile carriers and chip makers.
成员中,由开发Android的Google领衔,既包含手机制造商如HTC、Motorola、LG等,也包含了移动通信主要专利持有者及芯片提供商如高通(Qualcomm)、联发科(MediaTek)、爱立信(ST-Ericsson)等,也有其它手机芯片提供商德州仪器(Texas Instruments)、Marvell、博通(broadcom)、英伟达(NVIDIA)等,还有移动运营商如T-Mobile、中国移动等。更有三星(Samsung)、华为这种什么都沾边的巨无霸。
这可以说是囊括了手机壳子里面所有相关软硬件的一个全球性大联盟。
这是Google为了推出Android与Apple部落的iOS抗衡而组建的联盟,而现在回头,也明显看到了效果。Android超越了iOS,成为了市场份额第一。
Android必须碎片化
Android设备的屏幕分布。矩形代表屏幕大小,颜色深浅代表数量多少。虽然没有详查相关协议,但是Android作为联盟中连接各方的软件实体,其地位非同一般。如果哪天Google不再开源Android,那么联盟立刻瓦解。
Android从一开始,就肩负了拯救世界……呃呸,兼容不同硬件配置的手机设备的责任。Google与中游的移动通讯芯片提供商、下游的手机厂商,以及各种其它芯片、传感器的解决方案提供商,共同努力,才能补全一个完整的Android。Google一家,造不出一台Android手机(Nexus不仅代工,还代研)。
现在,一台Android手机的系统软件,开发流程通常是:
Google发布Android -> Qualcomm(or MediaTek)-> 手机厂商集成其它芯片的驱动 -> 手机厂商定制
为了让厂商能够闭源,Android不遵循GPL协议。这是一个“我开放,你基于我就必须开放”的传染式协议,是一些厂商不能接受的。尤其是一些解决方案提供商,把驱动的源码公开给竞争对手,基本上老底全泄光了。
Android不仅换成了允许商业闭源的Apache协议,还用各种方式把厂商需要修改的底层驱动,放到不会受Linux的GPL协议传染的地方。
开源Android,然后给手机厂商进行闭源再开发,这本就是题中应有之义。Android碎片化是一个计划内的必然结果。
其实碎片化不是问题,真正的问题是兼容性——明明是一个Android应用,却仍然无法正常运行;在那台手机好好的,换这台就不行。
Android的哲学
与iOS的封闭相对,Android的哲学核心就是开放。
不仅代码开源,而且实际运行的应用之间也有多种方式进行通信、协作,与iOS的隔离沙箱完全不同。
其次是替换。
除了Android kernel本身,任何应用都是可以替换的。桌面系统Launcher的抽屉式设计如果你不喜欢,可以换成各种其它桌面;图标看不惯,可以换各种其它主题。你可以用多款相机软件来使用同一个相机硬件,也可以用不同的通讯录软件来管理通讯录。理论上,除了【设置】以外(毕竟Google不可能知道下游的厂商在手机里安了什么硬件、需要怎么设置),其它软件都是可替换的。
什么都是可以选择的,这体现了一种自由的精神,一种软件之间开放竞争的理念。
当然,一些需要系统权限的功能,必须在System分区预置。
手机厂商的定制,从来就不是问题。与普通开发者相比,厂商无非就是通过预置在System分区可以获取系统权限。其它不需要系统权限的功能,Google、定制厂商、普通开发者,都在同一起跑线,可以自由竞争。
兼容性问题出在哪儿?
Google的问题
先说源头的Google。
CTS
为了保证Android在开放并且碎片化的前提下,能够有同样的兼容性,Google设计了CTS这样一个自动化测试。
CTS全称Compatibility Test Suite,兼容性测试工具,其实是指Google发布的一组测试Android手机兼容性的工具,仅支持Linux平台。
这套工具只是给系统平台开发者用的,也就是手机厂商的软件研发人员,所以相关资料不多。
这是一种自上而下,测试全套Android API及其系统资源是否有效的测试。如果某个API无法在调用后达成特定效果、返回正确的值,或者某张系统图片被改动了一个像素,都会导致测试失败。
每一台Android手机,即使是厂商定制的,都要通过CTS测试。只有在Google公司里,通过了全套CTS测试的手机,才被Google官方认可为Android的手机,才能显示“Powered by Android”并挂牌销售。
可以说,这套测试系统是Google对Android兼容性的最大努力。也正是因此,无论手机厂商做出了怎样的定制修改,都能支持正常的Android应用。
v4、v7、v13……
Android开发者对Android Support v4这个jar包都不会陌生,这是为了让Android v1.6及以后的一些低版本,能够使用一些高级版本才有的特性,而特别加入的。
4、7、13等,这些不是版本号,而是API Level,是与版本不同的另一套编号。基本上每一个重要的小版本改动,API Level都会加一。目前6.0的API Level是23。
这是一种向前兼容的努力。Google希望开发者在后来的新版本开发的应用,也能在一些比较老旧的版本里兼容。
此外,向后兼容,则是体现在对API的持续维护,尽量保证只增不减。
但是,目前的Android应用前后版本不兼容,往往体现为旧版本的一些应用在新版本不能用。这类有些是Android API维护问题,有大量@deprecated
的API。这些废弃接口不能保证在几个API Level后的版本仍然能正常使用。
新版本应用在旧版本不能用,往往体现在开发者没有使用v4等兼容包,或者手机机能限制无法支持。是开发者或用户的责任。当然,为了新版本而开发软件没有必要兼容旧版本,用户也没有义务更新手机硬件。责任是在那,但并没有错。只是不能把责任推给别人。
这些都是小问题。
Google Play Services
如果说CTS保证了每一个版本的横向兼容(比如,每一个基于Android 4.4定制的其它ROM,都要保证和原生Android 4.4兼容),那么v4等包则保证了纵向兼容(Android 4.4的应用能在Android 2.2的版本运行)。 这之中如果出现一些问题,也都是小问题。
导致闪退最多的因素就是缺乏Google Play Services。
Google Play是Google自家的Android应用商店,目前是全球最大的应用商店。很多在其中发布的应用,都依赖于Google在Android中预置的Google Play Services,以调用应用商店相关信息、Google+账户等内容。
而这个GoogleServicesFramework.apk,必须要在System分区才能起作用。
对其技术细节,我也不是很清楚,毕竟活在墙内。我不知道为什么这个apk需要这样做,但是在Android的系统架构上,它一定是可以不通过这种方式实现的。应用宝、360手机助手这种应用商店,就完全没要求厂商预置在系统分区,而是用户随时下载随时使用。
这个必须放在System分区的要求,就使得要么预置,要么伪装为预置(获取Root权限然后复制到/System/app/
下)。
这就是最大的问题,也是绝大多数Google Play上的Android应用闪退的原因!
一般来说,如果一个应用依赖于第三方类库、框架,例如各种.so、.jar文件,往往会自行在编译时设为Dependency,自带在APK里;如果依赖一个第三方APK,也可以打包在自家APK里,或者提示用户下载安装这个APK。
Google利用职务之便(发布Android系统给芯片提供商),改成了这种模式,直接造成了Android最大的兼容性问题。
Google Play 的野心
谷歌不是一家搜索广告公司,是一家研发公司。
这是Google高层对自己的界定。不得不说,非常了不起。
但是,商业公司都是逐利的,上市公司尤其如此。这一点,并不能被CEO的意志所改变。你可以不吃肉,也可以不吃素,但不能不吃饭。
无论Google在人们心中是什么形象,无论Google曾经为了技术或以外的什么因素而放弃了多少赚钱机会,都不能否认这一点,它是要逐利的。这也并没有什么不对。
从盈利的角度来看,Google大约90%的收入来源于广告,可以说是一家卖广告的公司。
Google组建开放手机联盟是为了推广Android,这个过程是无利的。推广Android是为了制造一个可以与封闭的iOS抗衡的大平台,这个过程是推动世界智能手机技术发展的。但是制造大平台还不够,因为Google不收Android的授权费(也正因为如此,Google不对下游提供技术支持),它是开源免费的。
这样,利益从何处来?
做Android的研发人员难道靠做搜索的来养?
答案就是Google Play应用商店,一个Android平台中的平台,完全由Google独家控制的大平台。在这里,Google可以继续卖广告。
但是,Google Play只是一个应用,不属于Android kernel。按照Android的设计哲学,它也是、或者说也应该是,可以替换的。
对开放手机联盟的背叛
用户、普通开发者,对开发手机联盟基本没有了解。甚至联盟内部的系统开发者,都对这事知之甚少,平时也闭口不提。
看小米科技大红大紫,其实它根本没加入这个联盟。而作为领跑者的HTC,如今在生死线上挣扎。我不禁要问,加入这个联盟有什么好处?
为什么在当代,中国大陆的智能手机飞速崛起,而海外(包括台湾省)的除了韩系三星、LG等,基本都风雨飘摇,既无大利润,也无大出货量?
这个问题很大,解答也很多,这里仅提出一个观点:那堵墙,逼迫中国厂商去除Google相关应用,换上自家做的。本来不情不愿地额外付出了研发成本,却意外地夺回了其中蕴含的巨大利益,并借此生存了下来。
小米直言“硬件不赚钱”,但由于牢牢把控了应用商店、视频、音乐、阅读、浏览器等平台,却获得了足以飞速发展的高额利润,同时也提高了中国用户的体验。而国外的厂商,强如HTC、Motorola,也只能赚一点辛苦的硬件差价,为Google做嫁衣。
应用商店,这一类基于Android的平台究竟该是谁的蛋糕?
既是Google的,也是厂商的,也是其它第三方平台的。可以说,就算Apple跑来做一个“Apk store”,也是符合Android规矩的。
而Google把Google Play预置在System分区,否则不可用,这种技术手段,直接掠夺了墙外相关组织的利益。通过预置和身在System分区的优势,强行提高竞争力,把国外所有第三方APK分发平台打得溃不成军。
这与Microsoft预置IE、QQ绑定各种自家应用、PC的360安全中心自动把360手机助手安装到插入电脑的Android手机上的这类做法,别无二致。
从某种意义上来说,Android是属于开放手机联盟的。可以说,没有这个联盟的推广,就没有Android的今天。如果各大公司各行其是,昔日的王者Symbian将持续演进,Windows Phone将不会惨淡,如三星BADA这样的大厂商自制系统也不会少见。
而如今,Android一统天下,联盟被Google用完就甩了。
本来大家以为Android是手机界的Linux,但其实它是一个可以让所有人看代码、可以让部分人修改分支代码、只有Google自己才能修改主线代码的Windows。
高通与联发科的问题
前面说过,高通(Qualcomm,也简称QC)和联发科(MediaTek,也简称MTK),是移动通讯相关技术的主要芯片提供商。此外,它们也是开发一个Android手机过程中的一个独立环节。手机厂商都是从这一环节发布的Android开始开发,而不是直接修改Google的版本。
Telephony完全不同
Android kernel,面向普通开发者的部分,主要是指frameworks/base
下编译出来的那个jar。而Telephony是指frameworks/opt/telephony
编译出来的jar,也包括部分apk。算是Android API下面实现层的一个组成部分。
Telephony下面是RIL( Radio Interface Layer ),负责和C/C++那一层对接。再下面就是Modem芯片了。Modem是智能手机作为“手机”的那部分功能的硬件,包括电话、短信、数据连接等,负责和移动基站交互。
以往Google是不太管Telephony的,往往都交给高通、联发科这样的芯片提供商来定制。这两家在Telephony可以说各逞手段,除了大概的架构,细节几乎完全不同!
比如,在Android 4.4及以前,Android手机是不能支持多张手机卡的。市面上的所有双卡双待,都是这两家自行定制,手机厂商再持续改良的结果。实现方案完全不同。
这直接导致了电话、短信等相关应用,基本无法被普通开发者开发,因为有大量的非API依赖。而各大厂商、甚至同一厂商不同型号的手机,这类应用都无法通用。
Google插手Telephony
在Android 5.0以后,Google开始介入Telephony的开发。但是由于版本碎片化,这并没有解决兼容性问题。最多就是可以期待以后的向后兼容。
不过,无情的事实打碎了这种美好的愿景。
整个Telephony在Android 5.0的大幅修改,换来的是与之前版本的完全不兼容。尤其是联发科一系,几乎全部特有实现都砍掉了。从实现方式看,很可能这是高通技术支持的结果,因此联发科成了这次版本变动最大的输家。
从Android 5.0到5.1,对所有用户、绝大多数开发者来说,基本没什么变化。但是对Telephony来说,又是一次翻天覆地的大变。
这两次改动,变化的类、接口、数据库字段等,实在太多。这里仅说一个:subId
。
Subscription Identification,是每一张电话卡在手机中的唯一标志符。第一插入的卡是1,此后在数据库中依次递增。在Android 4.4及以前,这是一个int类型;在Android 5.0,这变成了一个long类型;在Android 5.1以后,这又变成了一个int类型!
虽然这个东西,并不是对外(普通开发者)开放的,但也是处于整个Telephony模块核心地位,而且上层的部分系统应用都有涉及,改一动万,上下全乱。即使修改,也不能这样反复。这体现出了相关模块负责人的技术水平。
对Nexus以外的智能手机用户来说,这两个版本(5.0、5.1)在“智能”方面的功能可能问题不大,在“手机”方面的功能(驻网、识卡、电话、短信、数据连接等)都处于一个不稳定的状态。比如前面说的双卡双待功能,Google介入后,下游必须大幅改动、重新实现,造成额外开发成本,并降低了系统稳定性。如果在这两个版本的手机上发现相关bug或兼容性问题,十有八九是这个值的类型改动造成的蝴蝶效应所致。
联发科的手很长
和高通比,联发科在移动通讯的技术上是有很大差距的。不知道是不是因为在芯片技术上比不过,联发科对手机厂商提供的技术支持非常丰富而广泛。
联发科的手长,不仅体现在硬件上(除了CPU、Modem外还提供很多其它),也体现在软件上。高通在Telephony及相关的模块以外,修改较少,而联发科则到处都是!从系统应用,到framework,再到下面的各种C/C++层,到处都是它的爪印。用
// M: For some reason {
...
// }
这种东西包着的代码块就是了。
这就导致很多应用,在高通的Android手机上可以正常运行,在联发科的不可以。
比如视频播放软件,要播放MKV等格式,在很多联发科的手机上不支持硬件解码(即芯片本身不能解码播放),只能使用软件解码播放。而大多数视频软件根本不支持软件解码,这就导致软件闪退、视频无法播放等问题。
当然,也有少数反过来的情况。例如VPN,联发科的支持就比高通好些。
无论如何,高通和联发科在通讯技术以外的模块,多少都有介入,联发科尤其多。二者各显神通的结果,就是部分应用在这两类Android手机上不能同时兼容。
国内厂商的问题
去除Google Play Services
国内厂商定制Android ROM,通常第一步都是先去除Google Play Services。
这是被指责最多的一点,但是如前所述,一方面这是国情所限(部分仇恨转移到政府),另一方面这是Android生态“题中应有之义”(剩下仇恨转移回Google)。
这类闪退,主要原因还是Google把很多Android应用,诱拐为Google Play应用所致。
其实,从代码层面来讲是非常清楚的。
所有Android API在Java里import
时,都是import android.*
这种形式的,而属于Java语言本身的那部分,则是import java.*
。除了这二者之外,Android系统在原则上不提供任何其它方式的调用,要import
其它的class,请自备jar。
像import com.android.*
这种的,是系统内部自用的,不提供给普通开发者。
而import com.google.*
这种东西,和Android没有什么关系。
另外,从CTS的角度来讲,任何一台通过CTS的手机,都是Android手机;能够在某个版本以上的、通过CTS的所有手机上正常运行的应用,才是Android应用。因此依赖于Google Play Services的应用,本身就不具备Android需要的兼容性,这也是我为什么说“诱拐为Google Play应用”。
如果Google真的认为Google Play Services是Android不可分割的一部分,那么将其存在性检查加入CTS就好了。Why not?
不能在任意一台通过了CTS的手机上正常运行的应用,就不是一个兼容性良好的Android应用,而只是一个专有应用罢了。比如一个只能在华为手机上正常使用的应用,就只能算华为应用;一个只能在预置了Google Play的手机上运行的应用,就只是Google Play应用罢了。
所以,不是国内手机不兼容Google Play应用,而是Google Play的部分应用不兼容Android!
无脑定制与bug
厂商在定制的时候,很多在framework层的修改,是欠缺系统规划的。往往是这需要个功能,添加一个代码块;那有一个bug,添加一个代码块。
这些多余的东西,在普通应用调用相关API时,会产生额外的后果,有时会产生应用的功能不正常或直接崩溃。
最典型的就是,普通应用在某些情况下调一个API,接口内部的厂商代码块中发生概率性bug,丢异常,导致应用崩溃。
这类是厂商的软件工程师水平低下所致。
传感器问题
手机或受限于研发成本、或受限于技术限制、或受限于目标用户群体,在一些功能细节上是不一致的。
例如有些手机有温度传感器、气压传感器,最近的手机又开始一起安装指纹解锁、NFC等。这些都不是手机的必备硬件,是完全可以由厂商自主定制的。
而硬件上的不同,带来的应用功能失效,这也是兼容性问题的一种。比如一个测温度的应用,放到一个没有温度传感器的手机上,当然无法正常工作。
这就完全没办法了。
结语
一不小心写多了。
Google是Android应用兼容性问题最大的元凶!——其实我就是想把这个会被拍砖的观点,藏在标题以外的地方,并且让它显得合情合理一点,字数就上去了。
Google明明为了在Android必须碎片化(开放手机联盟)的前提下,保证应用兼容性而做出了多重努力(CTS、v4等兼容包),但还是自相矛盾地搞出了GoogleServicesFramework.apk必须放到System分区这种富含商业深意的技术设定。这体现了一家了不起的商业大公司,在拥有那样的领导人、那样的工程师文化的情况下,仍然也不得不时常屈服于逐利的本能需求。
篇幅头重脚轻,非是想对Google多加指责,对国内手机厂商随便说说。实是写到后面,精力不济、吐槽不能。
最后说下身份。我是某国内手机厂商的Android系统平台开发人员(仿佛看见一盆盆狗血往头上喷来),视角与常人不同,一些观点也难免受到自身立场影响。
技术和阅历有限,欢迎指正。