編輯:Android開發實例
Sensor即傳感器,在當前智能手機上大量存在:G-Sensor、LightsSensor、ProximitySensor、TemperatureSensor等,其作為Android系統的一個輸入設備,對於重視用戶體驗的移動設備來說是必不可少的。Sensor雖然是一個輸入設備,但是它又不同於觸摸屏,鍵盤,按鍵等這些常規的輸入設備,因為Sensor的數據輸入從傳感器硬件到設備的,而常規的輸入設備是從用戶到設備的,比如:溫度傳感器用於感知溫度的變化,采樣傳感器數據上報給設備。而傳感器硬件的工作與否,采樣精度是由用戶來控制的,所以對應Sensor而言是其工作方式是雙向的,即:控制硬件的控制流,硬件上報的數據流。這也決定了Sensor的框架不同與觸摸屏等常規輸入子系統。
本章節主要研究的Sensor框架代碼與SensorHAL的實現細節,一切還是從Sensor框架開始,首先來回顧下Led HAL的實現框架。
Led HAL是我們自己實現的,主要分為四部分:
Led App:Led的應用程序
Led Service框架:Led應用的API提供者
LedService本地:LedService服務的本地實現,上層與底層的通信轉化接口
Led HAL Stub:HAL層代碼,具體硬件驅動操作接口
很明顯,我們寫的Led HAL代碼是典型的控制流,反饋結果就是Led燈的亮與滅,它的架構不適用於Sensor架構,具體有如下幾點:
l Led是單純的控制流,而Sensor是控制流與數據流
Sensor的數據流不是實時的,而是有采樣速率,並且數據不是連續的,阻塞在讀取硬件設備數據上,只有數據得到才返回。
l Sensor是提供給所有傳感器的通用框架,不是針對某一特定硬件的架構
Sensor包含多種類型,在上層和底層都有對Sensor具體類型的屏蔽,讓它通用所有傳感器。
l Sensor的服務不是由應用程序創建啟動的,應該是伴隨系統啟動的
任何一個應用程序裡都可以使用Sensor服務,這決定了Sensor服務應該伴隨系統啟動。
本節是本系列第一個分析的具體設備的框架,從Android SensorService的注冊啟動開始,到應用程序獲得SensorManager注冊傳感器監聽器,詳細分析從應用層到Java框架層再到本地代碼,最後調用HAL層全部過程。
由前面Android啟動流程章節可知,Zygote啟動起來後,運行的每一個Java進程是SystemServer,它用來啟動並管理所有的Android服務:
public static void main(String[] args) {
…
System.loadLibrary("android_servers");
init1(args);
}
由SystemServer的main方法可知,其加載了libandroid_servers.so的庫,並且調用了init1()方法。
我們通過下面的命令來找到該庫的編譯目錄:
find ./frameworks/base –name Android.mk –exec grep –l libandroid_servers{}\;
通過打印的信息知道,其對應的源碼目錄在:frameworks/base/services/jni/下,其實Android框架層的代碼的特點就是Java目錄下存放的是對應的Java框架代碼,對應的jni目錄下是對應的本地代碼。
在這個目錄所有的代碼最重要的就是:com_android_server_SystemServer.cpp:
namespace android {
extern "C" int system_init();
static void android_server_SystemServer_init1(JNIEnv*env, jobject clazz)
{
system_init();
}
/*
* JNIregistration.
*/
static JNINativeMethod gMethods[] = {
/* name,signature, funcPtr */
{"init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1},
};
int register_android_server_SystemServer(JNIEnv* env)
{
returnjniRegisterNativeMethods(env, "com/android/server/SystemServer",
gMethods, NELEM(gMethods));
}
}; // namespace android
代碼不是很多,也比較好讀,調用jniRegisterNativeMethods方法注冊SystemServer的Java方法也本地方法映射關系,jniRegisterNativeMethods是一個本地方法的注冊Helper方法。
SystemServer.java在加載了libandroid_servers.so庫之後,調用了init1(),通過上面代碼中的映射關系可知,它調用了本地的android_server_SystemServer_init1方法,該方法直接調用system_init(),其實現在frameworks/base/cmds/system_server/library/system_init.cpp中實現:
extern "C" status_t system_init()
{
LOGI("Entered system_init()");
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
LOGI("ServiceManager: %p\n", sm.get());
sp<GrimReaper> grim = new GrimReaper();
sm->asBinder()->linkToDeath(grim, grim.get(), 0);
charpropBuf[PROPERTY_VALUE_MAX];
property_get("system_init.startsurfaceflinger", propBuf,"1");
if(strcmp(propBuf, "1") == 0) {
// Startthe SurfaceFlinger
SurfaceFlinger::instantiate();
}
property_get("system_init.startsensorservice", propBuf,"1");
if(strcmp(propBuf, "1") == 0) {
// Startthe sensor service
SensorService::instantiate();
}
LOGI("Systemserver: starting Android runtime.\n");
AndroidRuntime* runtime = AndroidRuntime::getRuntime();
LOGI("System server: starting Android services.\n");
JNIEnv* env =runtime->getJNIEnv();
if (env ==NULL) {
returnUNKNOWN_ERROR;
}
jclass clazz= env->FindClass("com/android/server/SystemServer");
if (clazz ==NULL) {
returnUNKNOWN_ERROR;
}
jmethodIDmethodId = env->GetStaticMethodID(clazz, "init2","()V");
if (methodId== NULL) {
returnUNKNOWN_ERROR;
}
env->CallStaticVoidMethod(clazz, methodId);
LOGI("System server: entering thread pool.\n");
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
LOGI("System server: exiting thread pool.\n");
}
如果了解Binder機制的話,應該知道,sp<ProcessState> proc(ProcessState::self())打開Binder驅動並會創建一個ProcessState對象並維持當前進程的Binder通信的服務器端。
如果系統屬性裡配置了system_init.startsensorservice 屬性為1,則通過SensorService::instantiate()啟動Sensor服務。
對於初學者最頭疼的就是追面向對象代碼中的重載,重寫的代碼了,SensorService::instantiate()調用的是其父類的方法,我們可以通過子類的定義找其繼承關系,然後順著繼承關系再來查找方法的實現,如果在子類裡和父類裡都有方法的實現,那麼看參數的匹配,如果參數都相互匹配,那麼就是所謂的重寫,調用的是子類的方法。SensorService的定義如下:
@frameworks/base/services/sensorservice/SensroService.h
class SensorService :
publicBinderService<SensorService>,
publicBnSensorServer,
protectedThread
{
通過SensorService的定義可知,在當前類裡沒有instantiate方法的聲明,說明其調用的是父類的方法,其繼承了BinderService,BnSensorServer,Thread類(難道SensorService是一個線程??),順著繼承關系找,在BinderService裡可以找到instantiate方法的聲明。
@frameworks/base/include/binder/BinderService.h
template<typename SERVICE>
class BinderService
{
public:
staticstatus_t publish() {
sp<IServiceManager> sm(defaultServiceManager());
returnsm->addService(String16(SERVICE::getServiceName()), new SERVICE());
}
static voidpublishAndJoinThreadPool() {
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
static void instantiate() { publish(); }
staticstatus_t shutdown() {
returnNO_ERROR;
}
};
通過上面代碼分析可知,instantiate方法創建了SensorService並通過addService將自己新創建的SensorService服務添加到Android服務列表裡了。
Ok,那我們來到SensorService服務中。
@frameworks/base/services/sensorservice/SensorService.cpp
SensorService::SensorService()
:mInitCheck(NO_INIT)
{
}
void SensorService::onFirstRef()
{
LOGD("nuSensorService starting...");
SensorDevice& dev(SensorDevice::getInstance());
…
SensorService的構造方法比較簡單,初始化了成員變量mInitCheck為NO_INIT。
要注意構造方法後面的onFirstRef方法,它是Android系統裡引用計數系統裡的一個方法。當RefBase的子類對象被第一次強引用時自動調用其方法,所以當第一次使用SensorService服務裡該方法被自動回調。
形如:
sp< ISensorServer> sm(mSensorService);
注:關於引用計數系統,如果讀者不太了解,請參考鄧凡平老師的:深入理解:Android系統核心 卷I中的三板斧部分。
SensorService的啟動到此暫停,等待上層應用的使用SensorService服務並調用onFirstRef方法。
轉自:http://blog.csdn.net/mr_raptor/article/details/8090474
一、啰嗦 之前有讀者反饋說,你搞這個所謂的最佳實踐,每篇文章最後就給了一個庫,感覺不是很高大上。其實,我在寫這個系列之初就有想過這個問題。我的目的是:給出最實用
Android提供了許多方法來控制播放的音頻/視頻文件和流。其中該方法是通過一類稱為MediaPlayer。Android是提供MediaPlayer類訪問內置的媒體播放
什麼是環境變量? 環境變量通常是指在操作系統當中,用來指定操作系統運行時需要的一些參數。通常為一系列的鍵值對。 path環境變量的作用 path環境變量是操作系統
登錄應用程序的屏幕,詢問憑據登錄到一些特定的應用。可能需要登錄到Facebook,微博等本章介紹了,如何創建一個登錄界面,以及如何管理安全問題和錯誤嘗試。首先,必須定義兩