背景
在国内由于广电总局的要求,互联网电视必须要拥有牌照才能播放网络影视资源,牌照方共有七个:国广东方CIBN、银河互联GITV、百视通BesTV、华数TV、南方传媒、芒果TV、未来电视(ICNTV)。
对于电视厂商来说,多样化的产品能够提升品牌竞争力,如何利用最少的资源来实现更多的功能?这是我们开发人员需要考虑的问题,那么体现在功能需求中便是:如何用一包代码支撑不同机型(也就是不同牌照方)。
优点
用同一包代码实现不同机型的功能,从工作量上来说节省了开发人力,也不需要重开Pack来应对CTS测试,另外在将来FOTA时也不需要多次编译,因为版本是共通的。
缺点
由于是把各家的服务集成到一包代码中,对用户来说,只能选择一种服务,那么剩余的服务会浪费掉一些系统存储空间。另外由于糅合的内容较多,代码维护的成本也会增加。
方案
集成牌照方,说白了就是集成不同的apk和服务,比如牌照方GITV的内容提供者是爱奇艺,那么需要集成爱奇艺的相关应用和服务,以及牌照方规定的一些定制化功能。
为区分不同的机型(牌照方),需要给每个机型配备独立的modelID,比如CIBN的modelID=1,GITV的modelID=2依次排序,系统开机时根据modelID来加载不同的服务和apk。
实现该方案的核心在于modelID,modeIID的独特作用决定了它的重要特性: 在系统还原时不能被清除(否则无法判断加载哪种服务)。userdata分区和system分区在系统还原时会被清除数据,不能满足这一特性,所以通常情况下modelID需要存放在独立的EEPROM(掉电后数据不丢失的存储芯片)中,然后在合适的节点对modelID进行设置和读取。
modelID的设置
由于用户拿到机器第一次开机时便需要指定牌照方,所以在工厂生产时便要对机器进行modelID的设置,生产流程中需要加入这一步骤。(不同厂商的实现方式不同,代码的实现没有共同性,所以就不贴啦~)
modelID的读取
机器开机时在boot阶段把modelID加载到bootagrs环境中,kernel加载结束后便在init进程中拿到modelID,并且为了方便使用该modelID,在init进程中,把该属性关联到到系统prop中,如ro.service.modelid ,系统服务PackageManagerService在扫描apk时根据prop加载不同的apk,即可实现针对不同modelID加载不同apk的功能。具体如下:
关键步骤1:Boot读取modelID
目录:fastboot/arch/arm/lib/board.c ,boot加载时执行函数start_armboot,在该函数中添加代码读取modeiID,并将参数拼接赋值给bootargs:setenv("bootargs",bootargs);
关键步骤2:Init进程读取modelID
在步骤1中,modelID已经加载到bootargs,kernel结束后加载init进程(目录:system/core/init/init.cpp)在函数main中读取bootargs获取modelID:
关键步骤3:PMS分包扫描
PackageManagerService开机时会扫描指定目录下的app和jar包,利用该特性,把不同牌照方的app编译到不同目录下,比如GITV的app编译到system/gitv/app目录下,CIBN的同理编译到system/cibn/app目录下,PMS根据modelID来动态扫描指定目录完成app的加载功能。
目录:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
app编译时指定目录,如:
总结
这种集成方案还是比较简单易懂的,另外就目前线上反馈来看还没有出现过严重问题,如果各位朋友有其他方案可以共同探讨探讨!