什麼是SystemService 我們在Android開發過程中經常會用到各種各樣的系統管理服務,如進行視窗相關的操作會用到視窗管理服務WindowManager,進行電源相關的操作會用到電源管理服務PowerManager,還有很多其他的系統管理服務,如通知管理服務NotifacationMana ...
什麼是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,利用單線程順序執行的特性,保證所有的訪問都按順序進行處理,但這種方法只適合單向的訪問,不適合需要返回的雙向訪問。