某些情況下,在系統研發時,需要加入自定義的SystemServer服務,以便為應用提供自定義的功能。
下面介紹如果添加自定義的SystemServer系統服務。
本示例基于Android 5.1版本,如果是其他的android版本,可參考。
以自定義DDTS服務為例,步驟如下:
1、建立自定義服務的aidl檔案
建立aidl檔案目錄:frameworks/base/core/java/android/app
在上面的目錄下,建立IDDTSManager.aidl檔案,aidl檔案中定義需要服務實作的接口
package android.app;
interface IDDTSManager {
boolean setValue(boolean val);
boolean getValue();
}
2、把aidl檔案添加到Android.mk中參與編譯
打開檔案:frameworks/base/Android.mk
在“LOCAL_SRC_FILES”變量中添加aidl的檔案。建議找到“app”目錄對應的分類,并在後面添加,這樣代碼工整點。
LOCAL_SRC_FILES += \
......
core/java/android/app/backup/IRestoreSession.aidl \
core/java/android/app/usage/IUsageStatsManager.aidl \
core/java/android/app/IDDTSManager.aidl \
core/java/android/wipower/IWipower.aidl \
3、建立DDTSManagerService.java檔案實作IDDTSManager.aidl中定義的接口
建立目錄:frameworks/base/services/core/java/com/android/server
PS:如果服務端檔案比較多,或者想把伺服器檔案放在同一個檔案夾下,可以建立個檔案夾存放
如:frameworks/base/services/core/java/com/android/server/DDTS,如果定義了自定義目錄,注意DDTSManagerService.java的包名
package com.android.server.DDTS
import android.content.Context;
pulic class DDTSManagerService extends IDDTSManager.stub {
private final Context mContext;
private boolean mVal;
public DDTSManagerService(Context context) {
mContext = context;
}
@Override
public boolean setValue(boolean val) {
mVal = val;
return true;
}
@Override
public boolean getValue() {
return mVal;
}
}
4、在SystemServer中注冊自定義的Service
打開檔案:frameworks/base/services/java/com/android/server/SystemServer.java
在private void startOtherServices()函數中添加自定義的Service
try {
Slog.i(TAG,"DDTS Service");
ServiceManager.addService(Context.DDTS_SERVICE, new DDTSManagerService(context));
} catch (Throwable e) {
reportWtf("starting DDTS Service fail:",e);
}
在addService中的Context.DDTS_SERVICE為服務端的名稱。
DDTS_SERVICE要在Context.java中添加
打開檔案:frameworks/base/core/java/android/content/Context.java
添加
public static final String DDTS_SERVICE = "ddts";
5、建立DDTSManager.java檔案
DDTSManager.java主要是給應用調用的類,DDTSManager通過binder調用到DDTSManagerService實作的aidl接口。完成最終的服務。
建立目錄:frameworks/base/core/java/android/app
package android.app;
import android.content.Context;
public class DDTSManager
{
private static IDDTSManager mService;
private final Context mContext;
DDTSManager(Context context) {
mContext = context;
mService = IDDTSManager.Stub.asInterface(ServiceManager.getService(Context.DDTS_SERVICE));
}
public boolean setValue(boolean val) {
try {
return mService.setValue(val);
} catch (RemoteException e){
return false;
}
}
public boolean getValue() {
try {
return mService.getValue();
} catch (RemoteException e){
return false;
}
}
}
6、把DDTSManager注冊到ContextImpl中
在ContextImpl.java中的static{}代碼中,添加注冊代碼,DDTSManager通過registerService函數注冊服務,這樣應用可以調用getSystemService擷取到DDTSManager,進而調用DDTSManager中的接口,最終調用到DDTSManagerService
registerService(DDTS_SERVICE,new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new DDTSManager(ctx.getOuterContext());
}});
7、添加SELinux Policy權限
打開檔案:external/sepolicy/service_contexts
在檔案中添加:
ddts u:object_r:system_server_service:s0
其中:ddts為SystemServer注冊服務時ServiceManager.addService函數中的Context.DDTS_SERVICE,也就是服務的名稱。
8、編譯framework.jar和Service.jar,并替換手機中的相應jar包。
寫一個apk測試服務是否能用。
1、在Android studio中建立一個android library的項目。
包名命名為:android.app(這個包名必須和DDTSManager.java的包名一緻)
并在android/app目錄下建立一個java檔案,檔案名稱和内容與DDTSManager.java一緻。
建立這個工程主要是因為要得到一個DDTSManager檔案對應的jar,把這個jar包放在apk工程中,這樣編譯apk時不會報錯。
2、建立一個apk工程,并把DDTSManager檔案對應的jar包放入到apk工程的libs目錄下。
把apk工程中的build.gradle檔案的dependecies中增加provided依賴
dependencies {
provided fileTree(include: ['*.jar'], dir: 'libs')
//compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:26.+'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
compile files('libs/DDTSManager.jar')
}
編譯好apk後,就可以在手機上驗證了。