android硬件访问服务程序框架
- loadLibrary 进行加载C库
- JNI_OnLoad 注册本地方法
– 分别调用各个硬件的函数来注册本地方法 - SystemServer 使用本地方法(在java代码中,例如InputManagerService),对每一个硬件构造service,将其添加到系统中
- APP 使用:获得服务 getService ;使用服务。执行service
SystemServer提供众多的服务service.
前三者属于系统进程
第四个属于用户进程
不同进程之间进行通信。所借助的是系统的binder服务。
以下属于针对上述分析
涉及的代码
\android5.0.2\frameworks\base\services\java\com\android\server\SystemServer.java
\frameworks\base\core\java\android\hardware\input\InputManager.java
\frameworks\base\services\core\java\com\android\server\input\InputManagerService.java
\frameworks\base\core\java\android\content\Context.java
\frameworks\base\core\java\android\app\ContextImpl.java
\frameworks\base\core\java\android\hardware\input\IInputManager.aidl
实例
//LoadLibrary加载C库
System.loadLibrary("android_servers");
nativeInit();
//...
startOtherServices();
//...
//利用本地方法,构造一个service InputManagerService 在这个java文件中嗲用native_init。从而跳转到了本地 inputManager = null;
inputManager = new InputManagerService(context);
//添加到系统中
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
//以上属于系统进程
//用户进程如何使用呢?
getSystemService(Context.INPUT_SERVICE);//就得到了这个服务。就可以通过service执行的一些操作
app使用
app的使用是调用getSystemService(Context.xxx来使用的)
getSystemService在Context.java中进行定义
public abstract Object getSystemService(@ServiceName @NonNull String name);
可以看出其为抽象的基类,其实现实在ContextImpl中实现的。
@Override
public Object getSystemService(String name) {
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
return fetcher == null ? null : fetcher.getService(this);
}
使用getSystemService获得的返回值,一般需要强转为一个Manager的类。
例如
mIm = (InputManager)Context.getSystemService(Context.INPUT_SERVICE);
问题
- nativeInit(); 是怎么关联本地方法
- 应用程序中自己LoadLibrary的话,另外一个app,是如何得到这个service的。其可能是通过aidl来获得这个服务的。这是和系统getSystemService不同的地方。getSystemService也是通过ServiceManager.getService来获得的。应用本身通过aidl来实现,android在编译的时候,自动实现了binder的机制。
注册本地方法
在JNI中实现
在onLoad.cpp中
android_server的实现
在framework/base/services下,
有一个Andrpid.mk
这个编译文件中,会将整个的Services目录的内容编译成两部分,
LOCAL_MODULE := services
LOCAL_MODULE:= libandroid_servers
目录下的java文件会编译为services
目录下jni下的
include
(wildcard
(LOCAL_PATH)/*/jni/Android.mk)
有android.mk包含的文件将会形成一个 动态库 android_service 供SystemServer进行调用。
JNI目录下的Android.mk
LOCAL_SRC_FILES += \
$(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_am_BatteryStatsService.cpp \
$(LOCAL_REL_DIR)/onload.cpp
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
frameworks/base/services \
frameworks/base/libs \
LOCAL_SHARED_LIBRARIES += \
libandroid_runtime \
主要是包含一些cpp文件、头文件以及需要的动态库文件
Load_Library的入口 onload.cpp
extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
调用
System.loadLibrary("android_servers");
的时候,会调用到JNI_OnLoad方法。
在这个方法中,会调用到和硬件相关的jni的cpp文件
register_android_server_PowerManagerService(env);
register_android_server_SerialService(env);
register_android_server_InputApplicationHandle(env);
register_android_server_InputWindowHandle(env);
register_android_server_InputManager(env);
register_android_server_LightsService(env);
register_android_server_AlarmManagerService(env);
register_android_server_UsbDeviceManager(env);
register_android_server_UsbHostManager(env);
register_android_server_VibratorService(env);
register_android_server_SystemServer(env);
register_android_server_location_GpsLocationProvider(env);
register_android_server_location_FlpHardwareProvider(env);
register_android_server_connectivity_Vpn(env);
register_android_server_AssetAtlasService(env);
register_android_server_ConsumerIrService(env);
register_android_server_BatteryStatsService(env);
register_android_server_hdmi_HdmiCecController(env);
register_android_server_tv_TvInputHal(env);
register_android_server_PersistentDataBlockService(env);
register_android_server_fingerprint_FingerprintService(env);
register_android_server_Watchdog(env);
服务的加载和被调用的过程
利用本地函数构造service是怎么样的过程呢?
答:在new InputManagerService的时候调用本地函数native_init
InputManagerService 继承IInputManager.stub
InputManagerService中提供相关的服务端的程序,供客户端调用。
在构造出service之后,利用
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
添加到ServiceManager中。
Context中InputManager的实话
在Context的实现类ContextImpl中,
registerService(INPUT_SERVICE, new StaticServiceFetcher() {
public Object createStaticService() {
return InputManager.getInstance();
}});
此时复写的createStaticService在调用getSystemService的时候被掉用。
在app应用中,需要使用这些Context的service的时候,调用
getSystemService(Context.xxx)同时将返回值强转为一个xxxManager类型。
InputManager 中通过getInstance获得 添加到ServiceManager的服务
public static InputManager getInstance() {
synchronized (InputManager.class) {
if (sInstance == null) {
IBinder b = ServiceManager.getService(Context.INPUT_SERVICE);
sInstance = new InputManager(IInputManager.Stub.asInterface(b));
}
return sInstance;
}
}
如此一来,客户端app就能通过binder机制,调用系统提供的服务了。
ClipboardService实例
抽象类
frameworks\base\core\java\android\text\ClipboardManager.java
实现类
frameworks\base\core\java\android\content\ClipboardManager.java
ClipboardManager中获取到服务
ClipboardManager clipboardManager =
(ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
ClipboardManager提供的一个方法。
clipboardManager.setText(expected);
在text目录下的ClipboardManger.java中的setText是一个抽象方法。
frameworks\base\core\java\android\text\ClipboardManager.java
public abstract void setText(CharSequence text);
在Content下的ClipbpadrManager.java实现了这个方法。故而调用如下代码
//首先调用InputManager下的setPrimaryClip
public void setText(CharSequence text) {
setPrimaryClip(ClipData.newPlainText(null, text));
}
//调用getService的setPrimaryClip
public void setPrimaryClip(ClipData clip) {
try {
if (clip != null) {
clip.prepareToLeaveProcess();
}
getService().setPrimaryClip(clip, mContext.getOpPackageName());
} catch (RemoteException e) {
}
}
//getService 通过ServiceManager获得clipboard的IBinder对象,并转换成为IClipboard 对象
static private IClipboard getService() {
synchronized (sStaticLock) {
if (sService != null) {
return sService;
}
IBinder b = ServiceManager.getService("clipboard");
sService = IClipboard.Stub.asInterface(b);
return sService;
}
}
// 通过aidl调用服务器部分的setPrimaryClip,这部分代码系统提供。
void setPrimaryClip(in ClipData clip, String callingPackage);
//aidl的实现
//ClipboardService
public void setPrimaryClip(ClipData clip, String callingPackage) {
synchronized (this) {
if (clip != null && clip.getItemCount() <= 0) {
throw new IllegalArgumentException("No items");
}
final int callingUid = Binder.getCallingUid();
if (mAppOps.noteOp(AppOpsManager.OP_WRITE_CLIPBOARD, callingUid,
callingPackage) != AppOpsManager.MODE_ALLOWED) {
return;
}
checkDataOwnerLocked(clip, callingUid);
final int userId = UserHandle.getUserId(callingUid);
PerUserClipboard clipboard = getClipboard(userId);
revokeUris(clipboard);
setPrimaryClipInternal(clipboard, clip);
List<UserInfo> related = getRelatedProfiles(userId);
if (related != null) {
int size = related.size();
if (size > 1) { // Related profiles list include the current profile.
boolean canCopy = false;
try {
canCopy = !mUm.getUserRestrictions(userId).getBoolean(
UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
} catch (RemoteException e) {
Slog.e(TAG, "Remote Exception calling UserManager: " + e);
}
// Copy clip data to related users if allowed. If disallowed, then remove
// primary clip in related users to prevent pasting stale content.
if (!canCopy) {
clip = null;
} else {
clip.fixUrisLight(userId);
}
for (int i = 0; i < size; i++) {
int id = related.get(i).id;
if (id != userId) {
setPrimaryClipInternal(getClipboard(id), clip);
}
}
}
}
}
}
总结
- 分析安卓系统时,需要记住android的c/s框架。SystemServer提供众多的service。这些service是由ServiceManager来进行管理的。注册时候需要使用ServiceManager.addService进行添加,客户端获取service,需要通过ServiceManager.getService来获取。
- Context上下文是和应用程序密切相关的。应用程序可以通过Context提供的getSystemService获取系统的服务,比如INPUT_SERVICE。
这些service的返回值通常是xxxManger 例如InputManager. 在这个xxxManager类中,调用了ServiceManager.getService。因此这个xxxManager就是在进一步的封装,提供了一些相关的方法。但是这些方法,最终还是通过获取的那个service,通过binder,调用系统提供的服务来实现的。 - 在系统和应用之前进行传递的是通过binder方式来进行的。在java层层面试下binder机制,需要使用AIDL。在aidl中定义接口,并在系统服务中实现这些接口,通常是实现接口的内部类stub。 并在SystemService中添加到系统中。