什么是SystemService
我們在Android開發程序中經常會用到各種各樣的系統管理服務,如進行視窗相關的操作會用到視窗管理服務WindowManager,進行電源相關的操作會用到電源管理服務PowerManager,還有很多其他的系統管理服務,如通知管理服務NotifacationManager、振動管理服務Vibrator、電池管理服務BatteryManager…… 這些Manager提供了很多對系統層的控制介面,對于App開發者,只需要了解這些介面的使用方式就可以方便的進行系統控制,獲得系統各個服務的資訊,而不需要了解這些介面的具體實作方式,而對于Framework開發者,則需要了解這些Manager服務的常用實作模式,維護這些Manager的介面,擴展這些介面,或者實作新的Manager,
一個簡單的SystemService
我們從一個簡單的系統服務Vibrator服務來看一下一個系統服務是怎樣建立的,
Vibrator服務提供的控制手機振動的介面,應用可以呼叫Vibrator的介面來讓手機產生振動,達到提醒用戶的目的,
從Android的官方檔案中可以看到Vibrator只是一個抽象類,只有4個抽象介面:
- bstract void cancel() 取消振動
- abstract boolean hasVibrator() 是否有振動功能
- abstract void vibrate(long[] pattern, int repeat) 按節奏重復振動
- abstract void vibrate(long milliseconds) 持續振動
應用中使用振動服務的方法也很簡單,如讓手機持續振動500毫秒:
Vibrator mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
mVibrator.vibrate(500);
Vibrator使用起來很簡單,我們再來看一下實作起來是不是也簡單,
從檔案中可以看到Vibrator只是定義在android.os 包里的一個抽象類,在原始碼里的位置即frameworks/base/core/java/android/os/Vibrator.java,那么應用中實際使用的是哪個實體呢?應用中使用的Vibrator實體是通過Context的一個方法getSystemService(Context.VIBRATOR_SERVICE)獲得的,而Context的實作一般都在ContextImpl中,那我們就看一下ContextImpl是怎么實作getSystemService的:
frameworks/base/core/java/android/app/ContextImpl.java
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
frameworks/base/core/java/android/app/SystemServiceRegistry.java
(SystemServiceRegistry是 Android 6.0之后才有的,Android 6.0 之前的代碼沒有該類,下面的代碼是直接寫在ContextImpl里的)
public static Object getSystemService(ContextImpl ctx, String name) {
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
SYSTEM_SERVICE_MAP是一個HashMap,通過我們服務的名字name字串,從這個HashMap里取出一個ServiceFetcher,再return這個ServiceFetcher的getService(),ServiceFetcher是什么?它的getService()又是什么?既然他是從SYSTEM_SERVICE_MAP這個HashMap里get出來的,那就找一找這個HashMap都put了什么,
通過搜索SystemServiceRegistry可以找到如下代碼:
private static <T> void registerService(String serviceName, Class<T> serviceClass,
ServiceFetcher<T> serviceFetcher) {
SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}
這里往SYSTEM_SERVICE_MAP里put了一對String與ServiceFetcher組成的key/value對,registerService()又是從哪里呼叫的?繼續搜索可以發現很多類似下面的代碼:
public class SystemVibrator extends Vibrator {
...
}
我們再從SystemVibrator看一下系統的振動控制是怎么實作的,以hasVibrator()為例,這個是查詢當前系統是否能夠振動,在SystemVibrator中它的實作如下:
public boolean hasVibrator() {
...
try {
return mService.hasVibrator();
} catch (RemoteException e) {
}
...
}
這里直接呼叫了一個mService.hasVibrator(),mService是什么?哪來的?搜索一下可以發現:
private final IVibratorService mService;
public SystemVibrator() {
...
mService = IVibratorService.Stub.asInterface(
ServiceManager.getService("vibrator"));
}
mService 是一個IVibratorService,我們先不去管IVibratorService.Stub.asInterface是怎么回事,先看一下IVibratorService是什么,搜索一下代碼發現這并不是一個java檔案,而是一個aidl檔案:
frameworks/base/core/java/android/os/IVibratorService.aidl
AIDL (Android Interface Definition Language) 是Android中的介面定義檔案,為系統提供了一種簡單跨行程通信方法,
IVibratorService 中定義了幾個介面,SystemVibrator中使用的也是這幾個介面,包括我們剛才使用的hasVibrator()
interface IVibratorService
{
boolean hasVibrator();
void vibrate(...);
void vibratePattern(...);
void cancelVibrate(IBinder token);
}
這里又只是介面定義,介面實作在哪呢?通過在frameworks/base目錄下進行grep搜索,或者在AndroidXRef搜索,可以發現IVibratorService介面的實作在frameworks/base/services/java/com/android/server/VibratorService.java
public class VibratorService extends IVibratorService.Stub
可以看到 VibratorService實作了IVibratorService定義的所有介面,并通過JNI呼叫到native層,進行更底層的實作,更底層的實作不是這篇檔案討論的內容,我們需要分析的是VibratorService怎么成為系統服務的,那么VibratorService是怎么注冊為系統服務的呢?在SystemServer里面:
VibratorService vibrator = null;
...
//實體化VibratorService并添加到ServiceManager
traceBeginAndSlog("StartVibratorService");
vibrator = new VibratorService(context);
ServiceManager.addService("vibrator", vibrator);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
...
//通知服務系統啟動完成
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeVibratorServiceReady");
try {
vibrator.systemReady();
} catch (Throwable e) {
reportWtf("making Vibrator Service ready", e);
}
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
這樣在SystemVibrator里就可以通過下面的代碼連接到VibratorService,與底層的系統服務進行通信了:
IVibratorService.Stub.asInterface(ServiceManager.getService("vibrator"));
mService相當于IVibratorService在應用層的一個代理,所有的實作還是在SystemServer的VibratorService里,
看代碼時可以發現registerService是在static代碼塊里靜態呼叫的,所以getSystemServcr獲得的各個Manager也都是單例的,
System Service實作流程
從上面的分析,我們可以總結出Vibrator服務的整個實作流程:
- 定義一個抽象類Vibrator,定義了應用中可以訪問的一些抽象方法
frameworks/base/core/java/android/os/Vibrator.java
- 定義具體的類SystemVibrator繼承Vibrator,實作抽象方法
frameworks/base/core/java/android/os/SystemVibrator.java
- 定義一個AIDL介面檔案IVibratorService,定義系統服務介面
frameworks/base/core/java/android/os/IVibratorService.aidl
- 定義服務VibratorService,實作IVibratorService定義的介面
frameworks/base/services/java/com/android/server/VibratorService.java
- 將VibratorServicey添加到系統服務
frameworks/base/services/java/com/android/server/SystemServer.java
VibratorService vibrator = null;
...
//實體化VibratorService并添加到ServiceManager
Slog.i(TAG, "Vibrator Service");
vibrator = new VibratorService(context);
ServiceManager.addService("vibrator", vibrator);
...
//通知服務系統啟動完成
try {
vibrator.systemReady();
} catch (Throwable e) {
reportWtf("making Vibrator Service ready", e);
}
- 在SystemVibrator中通過IVibratorService的代理連接到VibratorService,這樣SystemVibrator的介面實作里就可以呼叫IVibratorService的介面:
frameworks/base/core/java/android/os/SystemVibrator.java
private final IVibratorService mService;
...
public SystemVibrator() {
...
mService = IVibratorService.Stub.asInterface(
ServiceManager.getService("vibrator"));
...
public boolean hasVibrator() {
...
try {
return mService.hasVibrator();
} catch (RemoteException e) {
}
...
}
}
- 在Context里定義一個代表Vibrator服務的字串
frameworks/base/core/java/android/content/Context.java
public static final String VIBRATOR_SERVICE = "vibrator";
- 在ContextImpl里添加SystemVibrator的實體化程序
frameworks/base/core/java/android/app/ContextImpl.java
registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new SystemVibrator(ctx);
}});
- 在應用中使用Vibrator的介面
Vibrator mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
mVibrator.vibrate(500);
- 為保證編譯正常,還需要將AIDL檔案添加到編譯配置里
frameworks/base/Android.mk
LOCAL_SRC_FILES += \
...
core/java/android/os/IVibratorService.aidl \
System Service 新加介面
如果我們需要實作一個新的系統服務,就可以按照上面的步驟在系統中擴展出一個新的服務,并給應用層提供出使用介面,如果想在Vibrator里添加一個新的介面,需要下面3步:
- 在IVibratorService添加介面;
- 在VibratorService添加介面的實作;
- 在Vibrator及SystemVibrator里擴展新的介面;
這樣應用中就可以使用Vibrator的新介面了,
應用層與 System Service 通信
上面的實作我們看到的只是從應用層通過服務代理,呼叫系統服務的介面,如果我們想反過來,將系統服務的狀態通知給應用層,該怎么做呢?
- 方法一:使用Broadcast
我們知道使用Broadcast廣播可以實作跨行程的訊息傳遞,一些系統服務也使用了這種方法,如電池管理服務BatteryManagerService,收到底層上報的電池狀態變化資訊時,就將當前的電池狀態封裝在一個Intent里,action為android.intent.action.BATTERY_CHANGED,應用只要注冊一個對應的BroadcastReceiver就可以收到BatterManagerService發送的電池狀態資訊,
- 方法二:使用AIDL
從上面我們可以知道,通過AIDL定義一套介面,由系統服務端實作這些介面,應用端使用一個相應的代理就可以訪問系統服務的介面,那反過來讓應用端實作AIDL介面,系統服務端使用代理呼叫應用端的介面可不可以呢?答案是YES,那么接下來的問題是怎么讓系統服務得到這個代理,我們再來看一個LocationManager的例子,
//獲得定位服務
LocationManager locationManager =
(LocationManager) getSystemService(Context.LOCATION_SERVICE);
//定義定位監聽器
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
//監聽到位置資訊
}
...
};
//注冊監聽器
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
0, 0, locationListener);
從上面的代碼可以看到,我們創建了一個位置監聽器LocationListener,并將這個監聽器在LocationManager里進行了注冊,當系統定位到系統的位置后,就會回呼監聽器的onLocationChanged(),將位置資訊通知給監聽器,LocationListener就是一個系統服務呼叫應用層介面的例子,我們就研究一下LocationListener的實作方式,
我們先從LocationManager怎么注冊LocationListener開始研究:
frameworks/base/location/java/android/location/LocationManager.java
private final ILocationManager mService;
...
private void requestLocationUpdates(LocationRequest request,
LocationListener listener, Looper looper, PendingIntent intent) {
...
// wrap the listener class
ListenerTransport transport = wrapListener(listener, looper);
try {
mService.requestLocationUpdates(request, transport,
intent, packageName);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException", e);
}
}
可以看到LocationListener被重新封裝成了一個ListenerTransport,然后傳遞給了ILocationManager ,從前面的分析可以猜測到這個ILocationManager應該就是LocationManagerService的一個代理,那么ListenerTransport又是什么呢?搜索LocationManager.java可以找到:
private class ListenerTransport extends ILocationListener.Stub {
...
@Override
public void onLocationChanged(Location location) {
...
}
}
原來是ILocationListener.Stub的一個繼承實作,那么ILocationListener應該就是一個AIDL介面定義:
frameworks/base/location/java/android/location/ILocationListener.aidl
oneway interface ILocationListener
{
void onLocationChanged(in Location location);
...
}
而在LocationManagerService里只要呼叫ILocationListener的方法就可以將訊息傳遞給應用層的監聽:
mListener.onLocationChanged(new Location(location));
實作 System Service 的注意事項
- 注意防止阻塞
應用層訪問系統服務提供的介面時會有兩種情況:
一種是應用呼叫端需要等待服務實作端處理完成,回傳處理結果,這樣如果服務端發生阻塞,那么應用端也會發生阻塞,因此在實作服務端的實作時要注意不要發生阻塞,
另一種是呼叫端不需要等待服務端回傳結果,呼叫完成后直接回傳void,這樣服務端發生阻塞不會影響到應用端,這樣的單向的介面在AIDL里定義時需要添加oneway關鍵字,如:
oneway void statusBarVisibilityChanged(int visibility);
對于需要在服務端呼叫,在應用端實作的介面,考慮到系統的穩定性以及安全性,一般都會設計成上面的第二種,即AIDL里所有的介面都是單向的,如上面的ILocationListener
oneway interface ILocationListener
- 注意多執行緒訪問
每個系統服務在系統行程中只有一個實體,而且應用中系統服務的代理也是單例的,而且應用端的訪問,在系統行程都是使用獨立的執行緒進行回應,所以訪問同一個系統服務的介面時必然會出現多個執行緒或者多個行程同時訪問的情況,為保證系統服務的執行緒安全,需要對系統服務的行程進行多執行緒訪問的保護,目前主要有兩種實作執行緒安全的方法:
一種是通過同步鎖機制,鎖住一個物件實體(一般是這個服務物件本身),這樣這個服務同一時間只能回應一個訪問請求,如LocationManagerService里:
public boolean callStatusChangedLocked(...) {
...
synchronized (this) {
...
}
}
另一種方法就是使用Handler機制,這種服務一般會創建一個單獨的執行緒,當有應用端訪問請求到來時會向服務執行緒的Handler里發送一個Message,利用單執行緒順序執行的特性,保證所有的訪問都按順序進行處理,但這種方法只適合單向的訪問,不適合需要回傳的雙向訪問,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/28359.html
標籤:Android
