Android系統服務(SystemService)簡介


什么是SystemService

我們在Android開發過程中經常會用到各種各樣的系統管理服務,如進行窗口相關的操作會用到窗口管理服務WindowManager,進行電源相關的操作會用到電源管理服務PowerManager,還有很多其他的系統管理服務,如通知管理服務NotifacationManager、振動管理服務Vibrator、電池管理服務BatteryManager…… 這些Manager提供了很多對系統層的控制接口。對於App開發者,只需要了解這些接口的使用方式就可以方便的進行系統控制,獲得系統各個服務的信息,而不需要了解這些接口的具體實現方式。而對於Framework開發者,則需要了解這些Manager服務的常用實現模式,維護這些Manager的接口,擴展這些接口,或者實現新的Manager。

image

一個簡單的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服務的整個實現流程:

  1. 定義一個抽象類Vibrator,定義了應用中可以訪問的一些抽象方法
frameworks/base/core/java/android/os/Vibrator.java
  1. 定義具體的類SystemVibrator繼承Vibrator,實現抽象方法

frameworks/base/core/java/android/os/SystemVibrator.java

  1. 定義一個AIDL接口文件IVibratorService,定義系統服務接口

frameworks/base/core/java/android/os/IVibratorService.aidl

  1. 定義服務VibratorService,實現IVibratorService定義的接口

frameworks/base/services/java/com/android/server/VibratorService.java

  1. 將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);
}
  1. 在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) {
        }
        ...
    }
}
  1. 在Context里定義一個代表Vibrator服務的字符串

frameworks/base/core/java/android/content/Context.java

public static final String VIBRATOR_SERVICE = "vibrator";
  1. 在ContextImpl里添加SystemVibrator的實例化過程

frameworks/base/core/java/android/app/ContextImpl.java

registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
    return new SystemVibrator(ctx);
}});  
  1. 在應用中使用Vibrator的接口
Vibrator mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
mVibrator.vibrate(500);
  1. 為保證編譯正常,還需要將AIDL文件添加到編譯配置里

frameworks/base/Android.mk

LOCAL_SRC_FILES += \
...
core/java/android/os/IVibratorService.aidl \

System Service 新加接口

如果我們需要實現一個新的系統服務,就可以按照上面的步驟在系統中擴展出一個新的服務,並給應用層提供出使用接口。如果想在Vibrator里添加一個新的接口,需要下面3步:

  1. 在IVibratorService添加接口;
  2. 在VibratorService添加接口的實現;
  3. 在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 的注意事項

  1. 注意防止阻塞
    應用層訪問系統服務提供的接口時會有兩種情況:

一種是應用調用端需要等待服務實現端處理完成,返回處理結果,這樣如果服務端發生阻塞,那么應用端也會發生阻塞,因此在實現服務端的實現時要注意不要發生阻塞。

另一種是調用端不需要等待服務端返回結果,調用完成后直接返回void,這樣服務端發生阻塞不會影響到應用端,這樣的單向的接口在AIDL里定義時需要添加oneway關鍵字,如:

oneway void statusBarVisibilityChanged(int visibility);

對於需要在服務端調用,在應用端實現的接口,考慮到系統的穩定性以及安全性,一般都會設計成上面的第二種,即AIDL里所有的接口都是單向的,如上面的ILocationListener

oneway interface ILocationListener
  1. 注意多線程訪問

每個系統服務在系統進程中只有一個實例,而且應用中系統服務的代理也是單例的,而且應用端的訪問,在系統進程都是使用獨立的線程進行響應,所以訪問同一個系統服務的接口時必然會出現多個線程或者多個進程同時訪問的情況。為保證系統服務的線程安全,需要對系統服務的進程進行多線程訪問的保護,目前主要有兩種實現線程安全的方法:

一種是通過同步鎖機制,鎖住一個對象實例(一般是這個服務對象本身),這樣這個服務同一時間只能響應一個訪問請求,如LocationManagerService里:

public boolean callStatusChangedLocked(...) {
    ...
    synchronized (this) {
    ...
    }
}

另一種方法就是使用Handler機制,這種服務一般會創建一個單獨的線程,當有應用端訪問請求到來時會向服務線程的Handler里發送一個Message,利用單線程順序執行的特性,保證所有的訪問都按順序進行處理,但這種方法只適合單向的訪問,不適合需要返回的雙向訪問。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM