有些系统,因为应用场景的不同,需要的服务也不一样。比如Android Things,为了应对IOT的应用场景,它就裁剪掉了很多服务。下面介绍一下裁剪服务的方法。
关于服务,要提一下SystemServer,具体介绍见另一篇文章:。SystemServer启动了系统的核心服务,除此之外,SystemServer还启动了很多其他服务,具体是在startOtherServices()方法中。我们要裁剪不需要的服务就可以从这里入手。
比如要关闭打印机服务:
可以直接把相关启动服务的代码注释掉:
//mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS);当然这样修改后,以后如果要再打开,还需要再次修改SystemServer,然后编译jar包,push到设备使其生效。
所以建议使用下面的改法:
首先定义boolean变量,从全局属性读取配置,
boolean disablePrinter = SystemProperties.getBoolean("config.disable_printer", false);然后在启动服务的代码段添加对这个属性的判断:
if (!disablePrinter && mPackageManager.hasSystemFeature(PackageManager.FEATURE_PRINTING)) { mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS); }之后在MakeFile增加自定义的系统权限:
PRODUCT_PROPERTY_OVERRIDES += \ config.disable_printer=true以后如果要打开这个服务,就把true变成false就可以了。
如果要调试,从修改设备的 /system/build.prop 然后重启即可。非常方便有木有!
如果要修改,删掉out目录下的build.prop,重新编译system(或者直接修改build.prop然后make snod),烧录启动系统之后,运行如下命令进行验证:
service check printer这样就不会再启动不需要的服务了。
裁剪服务引发的问题服务不是你不让它Start就完事儿了,系统那么大,总有一些地方会获取服务对象做一些调用处理。比如我们刚裁减掉了打印机服务,然后打开Settings就遇到了crash:
E AndroidRuntime: FATAL EXCEPTION: main E AndroidRuntime: Process: com.android.settings, PID: 3496 E AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.settings/com.android.settings.Settings}: java.lang.NullPointerException: Attempt to invoke interface method 'java.util.List android.print.IPrintManager.getPrintServices(int, int)' on a null object reference E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2665) E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726) E AndroidRuntime: at android.app.ActivityThread.-wrap12(ActivityThread.java) E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477) E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:102) E AndroidRuntime: at android.os.Looper.loop(Looper.java:154) E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6119) E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:900) E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:790) E AndroidRuntime: Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'java.util.List android.print.IPrintManager.getPrintServices(int, int)' on a null object reference E AndroidRuntime: at android.print.PrintManager.getPrintServices(PrintManager.java:635) E AndroidRuntime: at android.print.PrintServicesLoader.onStartLoading(PrintServicesLoader.java:88) E AndroidRuntime: at android.content.Loader.startLoading(Loader.java:290) E AndroidRuntime: at android.app.LoaderManagerImpl$LoaderInfo.start(LoaderManager.java:283) E AndroidRuntime: at android.app.LoaderManagerImpl.installLoader(LoaderManager.java:579) E AndroidRuntime: at android.app.LoaderManagerImpl.createAndInstallLoader(LoaderManager.java:566) E AndroidRuntime: at android.app.LoaderManagerImpl.initLoader(LoaderManager.java:619) E AndroidRuntime: at com.android.settings.search.DynamicIndexableContentMonitor.register(DynamicIndexableContentMonitor.java:136) E AndroidRuntime: at com.android.settings.SettingsActivity.onStart(SettingsActivity.java:868) E AndroidRuntime: at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1249) E AndroidRuntime: at android.app.Activity.performStart(Activity.java:6737) E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2628) E AndroidRuntime: ... 9 more通过堆栈信息,可以知道PrintManager.getPrintServices出现了空指针。这里也不用看代码就能猜到,因为我们开机没有启动打印服务,所以肯定get不到这个服务的。
然后考虑修改方案,增加非空保护是不是就可以了?Naive!我们的目的是裁剪打印服务,所以我们的修改点并不在这个服务本身,而是删除所以调用这个服务的地方。
所以堆栈显示的PrintManager,PrintServicesLoader什么的统统不要改,我们要看代码结构,看看是怎么调用进来的。通过阅读代码,了解到系统里有很多Loader类型的对象,其中一个子类就是PrintServicesLoader。然后这些Loader是由LoaderManager管理启动的。而LoaderManager在DynamicIndexableContentMonitor.java出现过一次初始化操作。