1. 環境
クアルコム 865 Android10
2. サービスを追加するための具体的な手順
1.aidlファイルを追加する
フレームワーク/base/core/java/android/os/IMyService.aidl
package android.os;
interface IMyService{
int getSum(int data1,int data2);
}
フレームワーク/base/Android.bp
java_defaults {
名前: "フレームワークのデフォルト",
インストール可能: true、
ソース: [
// build/make/core/pathmap.mk から FRAMEWORK_BASE_SUBDIRS
"コア/java/**/*.java",
"グラフィックス/java/**/*.java",
"場所/java/**/*.java",
"ローパン/java/**/*.java",
......................
"core/java/android/os/IMyService.aidl",
]、
3. Aidl の特定の実装であるサービス ファイルを作成します。
フレームワーク/base/services/core/java/com/android/server/MyService.java
サービスのロジックは人によって異なる場合があります。サービスの定義は次のとおりです。
package com.android.server;
import android.os.IMyService;
import java.lang.Exception;
import android.os.RemoteException;
import android.util.Log;
import android.content.Intent;
import android.content.Context;
import android.os.SystemProperties;
import android.content.BroadcastReceiver;
import android.content.IntentFilter;
import android.app.AlarmManager;
import java.util.Calendar;
import android.app.PendingIntent;
import android.os.Build;
import android.os.SystemClock;
import android.text.TextUtils;
import java.util.concurrent.TimeUnit;
import java.io.IOException;
import android.os.Handler;
public class MyService extends IMyService.Stub{
private static final String ACTION_TIME_UPDATE_MINUTE = "com.vclusters.runshell.MINUTE_UPDATE_TIME";
private String TAG="MyService";
private Context mContext;
private PendingIntent mTimeUpdateIntent;
private AlarmManager mAlarmManager;
private boolean mHasRegistered;
public MyService(Context context){
mContext=context;
Log.d(TAG, "MyService <- is open6...");
try{
registerBroadcastReceiver();
startAlarm();
}catch (Exception exception){
Log.e(TAG, "MyService startTimerTask exception:"+exception.getMessage());
}
}
@Override
public int getSum(int data1,int data2) throws RemoteException{
return data1+data2;
}
private void removeTimeUpdateHourlyAlarm() {
if ((mTimeUpdateIntent != null) && (mAlarmManager != null)) {
// Log.d(TAG, "[removeTimeUpdateHourlyAlarm]#");
mAlarmManager.cancel(mTimeUpdateIntent);
}
}
private void startAlarm(){
Intent intent = new Intent();
intent.setAction(ACTION_TIME_UPDATE_MINUTE);
mTimeUpdateIntent = PendingIntent.getBroadcast(mContext, 100, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mAlarmManager= (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
setTimeUpdateHourlyAlarm();
}
}, 5000);//注意:服务中调用AlarmManager服务,这里延迟5秒加载,这里有坑,服务中立即使用服务,存在mAppOps还没加载,checkpackage()时报错问题
}
private void setTimeUpdateHourlyAlarm() {
if (mTimeUpdateIntent!=null&&mAlarmManager != null) {
Log.d(TAG, "[setTimeUpdateHourlyAlarm]#");
int actionShellTime = 1;
long triggerAtMills = SystemClock.elapsedRealtime() + TimeUnit.MINUTES.toMillis(actionShellTime);
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtMills, mTimeUpdateIntent);
}
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (TextUtils.equals(action, ACTION_TIME_UPDATE_MINUTE)) {
Log.d(TAG, "onReceive ACTION_TIME_UPDATE_MINUTE");
removeTimeUpdateHourlyAlarm();
setTimeUpdateHourlyAlarm();
}else if (TextUtils.equals(action, Intent.ACTION_TIME_CHANGED)) {
Log.d(TAG, "onReceive Intent.ACTION_TIME_CHANGED");
//removeTimeUpdateHourlyAlarm();
//setTimeUpdateHourlyAlarm();
}
}
};
private void registerBroadcastReceiver() {
if (mHasRegistered) {
return;
}
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(ACTION_TIME_UPDATE_MINUTE);
mContext.registerReceiver(mBroadcastReceiver, filter);
mHasRegistered = true;
}
private void unregisterBroadcastReceiver() {
if (mHasRegistered) {
mContext.unregisterReceiver(mBroadcastReceiver);
mHasRegistered = false;
}
}
}
4. MyService.java をシステム サービス マネージャーに追加します (つまり、起動時にサービスを開始します)。
フレームワーク/base/services/java/com/android/server/SystemServer.java
startOtherServices()
サービスを追加します
import com.android.server.MyService;
private void startOtherServices(){
traceBeginAndSlog("StartAlarmManagerService");
mSystemServiceManager.startService(new AlarmManagerService(context));
traceEnd();
traceBeginAndSlog("StartInputManagerService");
inputManager = new InputManagerService(context);
traceEnd();
...................//上面省略无关代码
Slog.i(TAG, "addService----MyService");
try {
ServiceManager.addService(Context.MY_SERVICE, new MyService(context));
} catch (Throwable e) {
Slog.e(TAG, "Failure starting MyService", e);
}
// 注意:添加服务最好添加到最后,例如,博主服务MyService.java中用到了AlarmManagerService,所以这//里的注册得放到AlarmManagerService后面,不然编译报错
}
5. 外部から利用できるインターフェースを作成します(アプリ内の getSystemService(String serviceName) で取得したサービスは、以下の MyServiceManager.java の関数を呼び出します)
フレームワーク/base/core/java/android/app/MyServiceManager.java
パッケージ android.app;
android.util.Log をインポートします。
android.os.IMyServiceをインポートします。
android.content.Contextをインポートします。
java.lang.Exceptionをインポートします。
android.os.RemoteExceptionをインポートします。
パブリック クラス MyServiceManager{
public static Final String TAG = "MyServiceManager";
プライベート IMyService mService;
public MyServiceManager(IMyService サービス){
mService = サービス;
}
public int getSum(int data1,int data2){
試す{
mService.getSum(data1,data2) を返します。
}catch(RemoteException e){
Log.e(TAG,"error getSum "+e.toString());
e.printStackTrace();
}
0を返します。
}
}
6. Contextでインターフェース名を設定します。
フレームワーク/ベース/コア/java/android/content/Context.java
public static final String MY_SERVICE ="myservice";
@StringDef(suffix = { "_SERVICE" }, value = {
POWER_SERVICE,
WINDOW_SERVICE,
LAYOUT_INFLATER_SERVICE,
ACCOUNT_SERVICE,
ACTIVITY_SERVICE,
ALARM_SERVICE,
NOTIFICATION_SERVICE,
ACCESSIBILITY_SERVICE,
CAPTIONING_SERVICE,
KEYGUARD_SERVICE,
LOCATION_SERVICE,
MY_SERVICE,
7. サービスを登録します (アプリ内の getSystemService() を呼び出してサービスを作成します)
フレームワーク/base/core/java/android/app/SystemServiceRegistry.java
import android.os.IMyService;
import android.app.MyServiceManager;
final class SystemServiceRegistry {
private static final String TAG = "SystemServiceRegistry";
// Service registry information.
// This information is never changed once static initialization has completed.
private static final Map<Class<?>, String> SYSTEM_SERVICE_NAMES =
new ArrayMap<Class<?>, String>();
private static final Map<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
new ArrayMap<String, ServiceFetcher<?>>();
private static int sServiceCacheSize;
// Not instantiable.
private SystemServiceRegistry() {
}
static {
//CHECKSTYLE:OFF IndentationCheck
registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,
new CachedServiceFetcher<AccessibilityManager>() {
@Override
public AccessibilityManager createService(ContextImpl ctx) {
return AccessibilityManager.getInstance(ctx);
}
});
................................//省略中间代码
registerService(Context.MY_SERVICE, MyServiceManager.class,
new CachedServiceFetcher<MyServiceManager>() {
@Override
public MyServiceManager createService(ContextImpl ctx) throws
ServiceNotFoundException {
IBinder b = ServiceManager.getServiceOrThrow(Context.MY_SERVICE);
if (b == null) {
return null;
}
IMyService service = IMyService.Stub.asInterface(b);
return new MyServiceManager(service);
}
});
}
3. 新しい API を追加した後、API を更新する必要があります
1、source build/envsetup.sh
2、lunch kona-userdebug
3、更新api(下面的命令如果没有执行,编译报错的时候会提示类似下面的命令,根据提示的命令执行,
不一定就是这里说的这两个命令去更新api)
make api-stubs-docs-update-current-api
或者make update-api
4、执行完步骤3后,current.txt会自动更新
frameworks/base/api/current.txt
类似下面这种:
field public static final String MY_SERVICE = "myservice";
public interface IMyService extends android.os.IInterface {
method public int getSum(int, int) throws android.os.RemoteException;
}
public static class IMyService.Default implements android.os.IMyService {
ctor public IMyService.Default();
method public android.os.IBinder asBinder();
method public int getSum(int, int) throws android.os.RemoteException;
}
public abstract static class IMyService.Stub extends android.os.Binder implements android.os.IMyService {
ctor public IMyService.Stub();
method public android.os.IBinder asBinder();
method public static android.os.IMyService asInterface(android.os.IBinder);
method public static android.os.IMyService getDefaultImpl();
method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
method public static boolean setDefaultImpl(android.os.IMyService);
}
4. Selinux 構成戦略 (構成権限がない場合、サービス内の関連 API は外部呼び出しに対してエラーを表示します)
1. 次の内容をファイル system/sepolicy/private/service_contexts に追加します。
myservice u:object_r:myservice_service:s0
2. 次のコンテンツをファイル system/sepolicy/prebuilts/api/29.0/private/service_contexts に追加します。
system/sepolicy/prebuilts/api/29.0/private/service_contexts
3. 次の内容をファイル system/sepolicy/public/service.te に追加します。
type myservice_service, system_api_service, system_server_service, service_manager_type;
4. 次のコンテンツをファイル system/sepolicy/prebuilts/api/29.0/public/service.te に追加します。
タイプ myservice_service、system_api_service、system_server_service、service_manager_type;
注: 次の 2 つのファイルの内容はまったく同じである必要があり、あと 1 行のスペースは機能しません。
システム/sepolicy/public/service.te
system/sepolicy/prebuilts/api/29.0/public/service.te
他の API および 29.0 に対する同様の追加:
system/sepolicy/prebuilts/api/28.0/public/service.te
system/sepolicy/prebuilts/api/27.0/public/service.te
system/sepolicy/prebuilts/api/26.0/public/service.te
system/sepolicy/prebuilts/api/28.0/private/service_contexts
system/sepolicy/prebuilts/api/27.0/private/service_contexts
system/sepolicy/prebuilts/api/26.0/private/service_contexts
//经测试,只添加system/sepolicy/29.0,上面的没添加编译会报错,最好都添加上
5、コンパイル
6. サービスが正常に追加されたかどうかを確認します
1. サービス名から定義したサービスが存在するか確認します。
サービス名は、Context.txt で上で定義したサービス名です。
パブリック静的最終文字列 MY_SERVICE ="myservice";
2. 接続カードを使用して、Android Studio のサービスのログを表示することもできます
7. アプリは追加されたサービスを利用します
编译生成的代码位置:
out\target\common\obj\JAVA_LIBRARIES\framework_intermediates\classes.jar 包含代码的
out\target\common\obj\JAVA_LIBRARIES\framework_intermediates\classes-header.jar 这个就只有方法名, 不提供内容实现代码
如果不想要把整个framework层代码提供出去,还有一种简单的方法, 自己新建个app,打成jar包,包名和framewrok层写的一样,最后打包成一个jar包,compileOnly files(‘libs\classes.jar’) 这样使用
使用示例:
MyServiceManager myServiceManager=(MyServiceManager)getSystemService("myservice");
int sumVlaue=myServiceManager.getSum(2,3);