Lights是Android里面一个相对比较简单但是重要的子系统,通过Lights的服务,手机才得以控制亮屏、灭屏,呼吸灯,按键灯等跟LED相关的功能。本文将对几种常用的灯做简单的介绍。
Android设备中的原生的LED灯的类型可以查看下面的文件
frameworks/base/services/core/java/com/android/server/lights/LightsManager.java
22 public static final int LIGHT_ID_BACKLIGHT = Type.BACKLIGHT;
23 public static final int LIGHT_ID_KEYBOARD = Type.KEYBOARD;
24 public static final int LIGHT_ID_BUTTONS = Type.BUTTONS;
25 public static final int LIGHT_ID_BATTERY = Type.BATTERY;
26 public static final int LIGHT_ID_NOTIFICATIONS = Type.NOTIFICATIONS;
27 public static final int LIGHT_ID_ATTENTION = Type.ATTENTION;
28 public static final int LIGHT_ID_BLUETOOTH = Type.BLUETOOTH; //暂时未启用
29 public static final int LIGHT_ID_WIFI = Type.WIFI; //暂时未启用
每种ID的灯的详情如下 | 名称 | Light ID | 对应节点文件 | 执行函数(lights.c) | 备注 | | :——— | :———- | :————– | :————- |:———- |
背光灯 | LIGHT_ID_BACKLIGHT | LCD_FILE | set_light_backlight | 背光灯,只操作亮度 |
键盘灯 | LIGHT_ID_KEYBOARD | KEYBOARD_FILE | set_light_keyboard | 键盘灯,只操作亮、灭 |
按键灯 | LIGHT_ID_BUTTONS | BUTTON_FILE | set_light_buttons | 按键灯(经常和上面是同一个灯) |
充电指示灯 | LIGHT_ID_BATTERY | red, blue,green | set_light_battery | 一般跟通知灯是同一个,只能在BatteryService中调用 |
通知灯 | LIGHT_ID_NOTIFICATIONS | red, blue,green | set_light_notifications | 只在NotificationManagerService中调用,只会在灭屏的时候闪烁通知等,且每次亮屏关闭,调用updateLightsLocked。 |
LIGHT_ID_ATTENTION | TRACKBALL_FILE | set_light_attention | LIGHT_FLASH_HARDWARE这个闪灯模式 | |
LIGHT_ID_BLUETOOTH | 暂时未启用 | |||
LIGHT_ID_WIFI | 暂时未启用 |
本文从AndroidStudio的Lint对Handler的警告入手,初步窥探Handler不恰当定义可能引起的内存泄漏的原因,不涉及Handler的实现原理分析.
使用下面的方式定义一个Handler,AndroidStudio会弹出提醒,表示可能存在内存泄漏的风险。
Lint的提示信息翻译如下:
Handler被声明为内部类,可能会阻止外部类被回收。如果Handler不是使用主线程中的Looper或者MessageQueue,那么就没有此问题。但是如果Handler使用的是主线程的Looper或者MessageQueue,那么需要将其作为一个静态类,并在Handler初始化的时候将外部类实例对象以弱引用的方式传递给Handler
在理解上面这段话之前,我们先来看下外部类和内部类的一些信息。
内部存储和外部存储的概念随着Android版本的更新也在发生不断的变化。最早的内部存储指的是系统自带的ROM存储,外部存储指的是外置的Sdcard或者通过OTG挂在的USB存储。随着硬件价格越来愈低,系统内置的ROM也越来越大,现在即使是一台千元机,一般存储容量也是在16GB以上。所以在Android 4.4以后,系统将内部存储分为了Internal Storage和External Storage。而原来的外置Sdcard或者通过OTG挂载的USB,也都是属于External Storage。
内部存储指的是应用内部独有的存储,这部分存储的文件、数据,只能被应用自身访问到,其他应用都没有权限访问。
一般情况下,/data开头的路径都是Internal Storage。而一般应用所能够访问到的就是下面几个路径,称为应用内部私有存储。
应用内部私有存储:
/data/user/0/<包名>包名>
/data/user/0/<包名>/files #存放文件数据包名>
/data/user/0/<包名>/databases #存放Sqlite的数据库文件包名>
/data/user/0/<包名>/shared_prefs #存放SharedPreference的数据包名>
/data/user/0/<包名>/cache #存放缓存文件包名>
AIDL常被用来快速创建Binder服务,但大多应用在Java层的客户端、服务端接口代码生成,其实它也可以用来创建Native层的接口服务。当前网上关于Native层AIDL使用的说明和资料并不是很多,本文将会简单的介绍下相关的使用方式。
AIDL作为一种DSL语言,通过代码生成的方式,让开发者用相对简单的方式,将Binder客户端和服务端的接口代码给生成,使得开发者可以将更多的精力放在接口的实现方面。
一般我们接触Java相关的代码生成会比较多,如下图所示
创建的Binder服务我们可以通过下面的方式使用
由于工作的需要,需要创建Native层的Binder服务,供Native层的系统服务使用。但是网上关于AIDL生成Binder的资料少之又少,最具有参考价值的就是Google doc里面关于AIDL-CPP的介绍,https://android.googlesource.com/platform/system/tools/aidl/+/brillo-m10-dev/docs/aidl-cpp.md
Google关于AIDL-CPP这篇文档是非常有价值去仔细研读的。上面大致介绍了hidl-cpp的引入时间,什么时候会生成Java的代码,什么条件下又是生成CPP的代码,Java与C++的一些基本类型的转换等等。 但是即使有这篇Doc,想要自己通过AIDL创建Native层的Binder服务,还是需要花费不少的时间,踩不少的坑。
既然没有现成的资料可以参考,那么只有通过阅读和学习AOSP的代码,参考Google是如何直接或者通过AIDL创建Native层服务的。本文参考的是Andorid 8.1的代码。
frameworks/base/core/java/android/os/IPowerManager.aidl
frameworks/native/include/powermanager/IPowerManager.h
frameworks/native/services/powermanager/IPowerManager.cpp
虽然PowerManager定义了IPowerManager.aidl,但是这个AIDL只会生成Java层的代码,因为包含这个文件的模块最终生成的是frameworks.jar。但是由于PowerManager很多服务需要被Native层的服务所使用。
所以PowerManager在Native层定义了IPowerManager.h和IPowerManager.cpp文件,能够让Native的代码调用PowerManagerService的服务。比如说某个Native代码想要通过PowerManagerService申请WakeLock,这一通过下面的代码获取PowerManagerService的服务实例。
frameworks/av/media/libstagefright/foundation/AWakeLock.cpp
if (mPowerManager == NULL) {
// use checkService() to avoid blocking if power service is not up yet
//获取PowerManager的服务
sp<IBinder> binder =
defaultServiceManager()->checkService(String16("power"));
if (binder == NULL) {
ALOGW("could not get the power manager service");
} else {
mPowerManager = interface_cast<IPowerManager>(binder);
binder->linkToDeath(mDeathRecipient);
}
}
if (mPowerManager != NULL) {
sp<IBinder> binder = new BBinder();
int64_t token = IPCThreadState::self()->clearCallingIdentity();
//申请Wakelock
status_t status = mPowerManager->acquireWakeLock(
POWERMANAGER_PARTIAL_WAKE_LOCK,
binder, String16("AWakeLock"), String16("media"));
}
通过对PowerManager实现的参考,首先实现了在不通过AIDL创建Native层的服务,后续介绍如何自定义服务。
frameworks/av/camera/aidl/android/hardware/ICameraService.aidl frameworks/av/services/camera/libcameraservice/CameraService.h frameworks/av/services/camera/libcameraservice/CameraService.cpp
Camera在Java层只有一个CameraManager,其服务的实现都是在Native层。无论是API1还是API2,最终都会调用到Native层的CameraService,由CameraService作为入口对Camera的HAL1或者HAL3进行操作。 frameworks/av/camera/aidl/android/hardware/ICameraService.aidl最终会在下面路径下(64位的路径)生成Binder所需要的接口文件 out/soong/.intermediates/frameworks/av/camera/libcamera_client/android_arm64_armv8-a_cortex-a53_shared_core/gen/aidl 会生成下面几个文件 ICameraService.h 功能接口文件 BpCameraService.h 客户端 BnCameraService.h 用来被服务端继承 ICameraService.cpp Binder通讯的实现
这些类在CameraService.h和CameraService.cpp被继承使用,类的关系如下图所示
本文基于Android O平台进行分析
Android.mk对于熟悉Android源码的人来说并不陌生,虽然Google开始逐步用Android.bp来替换Android.mk,但是其实质并没有发生什么变化,只是又在Android.mk的基础上又封装了一层。
本文基于MTK平台的Android8.1进行分析
Selinux在Android M之后被要求强制开启,主要用来描述一些domain对系统中的资源,如文件、系统属性,socket之类的访问的限制。而在Android系统中,Application中的应用根据一些条件被分为了好几类domain。 在开发的过程中会遇到有些APP不能读写系统属性,有些app能够访问节点的节点却不能被某些app却不能,就是因为这些app所属于的SELinux domain不同。 本文将会对这些进行介绍。
abd shell之后通过ps -AZ查看进程