記事ディレクトリ
私のナレッジ プラネットAndroid システム開発ガイド へようこそ 。WeChat パブリック アカウントWuxian
のフォローへようこそ 。Zhihuアカウント Wuxian のフォローへようこそ。
前の記事では、カスタム Java システム サービスを追加する最初の方法を紹介しました (最初に読むことをお勧めします)。この方法では、サービスはシステムのキー プロセス system_server で実行されます。コードがクラッシュすると、システムを再起動します。このセクションでは、問題が発生したときにシステムの安定性に影響を与えないように、カスタム サービスを独立したプロセスで実行する別の方法を紹介します。
このメソッドの重要な点は、サービス実装をカスタム プロセスに配置し、クライアントがバインダーを通じてサービス実装を呼び出すと、カスタム プロセスで実行されるようにすることです。このセクションの例では、完全な例を確実にするために、それに新しい名前 melon を付けます。
エイドルを定義する
// frameworks/base/core/java/android/melon/IMelonManager.aidl
package android.melon;
import android.melon.Person;
/**
* {@hide}
*/
interface IMelonManager {
void sayHello(String words);
// 自定义类型前面必须加上in或者out或者inout标识符
// in: 表示参数只能由客户端传递到服务端,基本类型默认只支持in修饰符
// out: 表示参数只能由服务端传递到客户端,服务端如果修改了参数对象的值
// 那么客户端的值也会改变,但是服务端无法读取客户端对象的值
// inout: 表示参数可以双向传递
void sayHelloTo(in Person person, String words);
}
カスタム クラス Person の定義は、クライアントとサーバーの間でオブジェクト データを転送するために使用されます。
// frameworks/base/core/java/android/melon/Person.java
package android.melon;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
public final class Person implements Parcelable {
private String mName;
private int mAge;
public Person() {
}
public Person(@NonNull String name, int age) {
this.mName = name;
this.mAge = age;
}
private Person(@NonNull Parcel in) {
this.mName = in.readString();
this.mAge = in.readInt();
}
@NonNull
public String getName() {
return mName;
}
public int getAge() {
return mAge;
}
public void setName(@NonNull String name) {
mName = name;
}
public void setAge(int age) {
mAge = age;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(this.mName);
dest.writeInt(this.mAge);
}
public void readFromParcel(@NonNull Parcel source) {
this.mName = source.readString();
this.mAge = source.readInt();
}
@NonNull
public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
@Override
public Person createFromParcel(@NonNull Parcel source) {
return new Person(source);
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
}
// frameworks/base/core/java/android/melon/Person.aidl
package android.melon;
parcelable Person;
クライアントを定義する
- Context.javaでサービス名を定義する
// frameworks/base/core/java/android/content/Context.java
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6ad91d26daf7..6e7ba7795e09 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3810,6 +3810,7 @@ public abstract class Context {
ACTIVITY_SERVICE,
ALARM_SERVICE,
BEAN_SERVICE,
+ MELON_SERVICE,
NOTIFICATION_SERVICE,
ACCESSIBILITY_SERVICE,
CAPTIONING_SERVICE,
@@ -4259,6 +4260,16 @@ public abstract class Context {
*/
public static final String BEAN_SERVICE = "bean";
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.melon.MelonManager} for interacting with the global
+ * system state.
+ *
+ * @see #getSystemService(String)
+ * @see android.melon.MelonManager
+ */
+ public static final String MELON_SERVICE = "melon";
+
/**
* Use with {@link #getSystemService(String)} to retrieve a
* {@link android.app.ActivityTaskManager} for interacting with the global system state.
- MelonManager.javaを定義し、バインダークライアントをカプセル化します。
// frameworks/base/core/java/android/melon/MelonManager.java
package android.melon;
import android.annotation.NonNull;
import android.content.Context;
import android.os.RemoteException;
import android.util.Log;
/**
* {@hide}
*/
public class MelonManager {
private static final String TAG = "MelonManager";
private Context mContext;
private IMelonManager mService;
public MelonManager(IMelonManager service, Context ctx) {
Log.d(TAG, "new MelonManager");
mService = service;
mContext = ctx;
}
public void sayHello(@NonNull String words) {
Log.d(TAG, "sayHello words: " + words);
if (mService == null) {
Log.d(TAG, "sayHello mService is null!!!");
return;
}
try {
mService.sayHello(words);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
public void sayHelloTo(@NonNull Person person, @NonNull String words) {
Log.d(TAG, "sayHelloTo " + person.getName() + ": " + words);
if (mService == null) {
Log.d(TAG, "sayHello mService is null!!!");
return;
}
try {
mService.sayHelloTo(person, words);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
- Context.getSystemService(Context.MELON_SERVICE)で取得したサービスのプロキシカプセル化クラスMelonManagerを取得できるようにMelonManager.javaを構築します。
// frameworks/base/core/java/android/app/SystemServiceRegistry.java
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 8947e19dd0a6..4b71a0e015ba 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -136,6 +136,8 @@ import android.media.tv.interactive.ITvInteractiveAppManager;
import android.media.tv.interactive.TvInteractiveAppManager;
import android.media.tv.tunerresourcemanager.ITunerResourceManager;
import android.media.tv.tunerresourcemanager.TunerResourceManager;
+import android.melon.IMelonManager;
+import android.melon.MelonManager;
import android.nearby.NearbyFrameworkInitializer;
import android.net.ConnectivityFrameworkInitializer;
import android.net.ConnectivityFrameworkInitializerTiramisu;
@@ -344,6 +346,16 @@ public final class SystemServiceRegistry {
return new BeanManager(service, ctx);
}});
+ registerService(Context.MELON_SERVICE, MelonManager.class,
+ new CachedServiceFetcher<MelonManager>() {
+ @Override
+ public MelonManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getServiceOrThrow(Context.MELON_SERVICE);
+ IMelonManager service = IMelonManager.Stub.asInterface(b);
+ return new MelonManager(service, ctx);
+ }});
+
+
registerService(Context.AUDIO_SERVICE, AudioManager.class,
new CachedServiceFetcher<AudioManager>() {
@Override
サーバーの定義
サーバーは新しいプロセスを作成する必要がありますが、Java レイヤー サービスであるため、システム アプリ プロセスをカスタマイズする必要があり、コンピューターの電源が入ったときにプロセスが開始されます。永続属性の追加、ブート ブロードキャストの受信など、システム アプリケーションが起動時に自動的に起動するためのソリューションは数多くあります。ここでは、永続属性を追加する方法を使用します。これはアプリであるため、PMS がアプリを解析した後にのみ開始できます。システムは最初に永続アプリケーションを開始します。これにより、アプリケーションがより早く正常に開始されることが保証されます。
- カスタム システム サービス アプリケーションを作成する
Android.bp コンパイル済みファイル
// vendor/zzh/apps/MelonService/Android.bp
android_app {
name: "MelonService",
srcs: [
"app/src/main/java/**/*.java",
],
resource_dirs: [
"app/src/main/res",
],
privileged: true,
manifest: "app/src/main/AndroidManifest.xml",
platform_apis: true,
certificate: "platform",
libs: [
"framework",
],
static_libs: [
"androidx.annotation_annotation",
],
}
AndroidManifest.xml ファイルには、次の属性を追加する必要があることに注意してください。
android:sharedUserId="android.uid.system"
coreApp="true"
android:directBootAware="true"
android:persistent="true"
// vendor/zzh/apps/MelonService/app/src/main/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:sharedUserId="android.uid.system"
package="com.zzh.melonservice"
coreApp="true">
<application
android:name=".MelonApplication"
android:label="@string/app_name"
android:supportsRtl="true"
android:directBootAware="true"
android:persistent="true"
tools:targetApi="31" >
</application>
</manifest>
// vendor/zzh/apps/MelonService/app/src/main/java/com/zzh/melonservice/MelonApplication.java
package com.zzh.melonservice;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT;
import android.app.Application;
import android.content.Context;
import android.os.ServiceManager;
import android.util.Log;
public class MelonApplication extends Application {
private static final String TAG = "MelonApplication";
private MelonManagerService mService;
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
// 调用ServiceManager.addService注册服务
mService = new MelonManagerService(getApplicationContext());
ServiceManager.addService(Context.MELON_SERVICE, mService, false, DUMP_FLAG_PRIORITY_DEFAULT);
}
@Override
public void onTerminate() {
super.onTerminate();
Log.d(TAG, "onTerminate");
}
@Override
public void onLowMemory() {
super.onLowMemory();
Log.d(TAG, "onLowMemory");
}
}
// vendor/zzh/apps/MelonService/app/src/main/java/com/zzh/melonservice/MelonManagerService.java
package com.zzh.melonservice;
import android.content.Context;
import android.melon.IMelonManager;
import android.melon.Person;
import android.util.Log;
public class MelonManagerService extends IMelonManager.Stub {
private static final String TAG = "MelonManagerService";
private Context mContext;
public MelonManagerService(Context context) {
Log.d(TAG, "MelonManagerService");
mContext = context;
}
@Override
public void sayHello(String words) {
Log.d(TAG, " sayHello : " + words);
}
@Override
public void sayHelloTo(Person person, String words) {
Log.d(TAG, " sayHello " + person.getName() + ": " + words);
}
}
- プロジェクトの構成ファイルに selinux 権限を追加します。
// vendor/zzh/sepolicy/private/service_contexts
melon u:object_r:melonserver_service:s0
// vendor/zzh/sepolicy/public/service.te
type melonserver_service, service_manager_type;
// vendor/zzh/sepolicy/public/system_app.te
allow system_app melonserver_service:service_manager add;
場合
Launcher の起動時にカスタム サービスを呼び出します
// packages/apps/Car/Launcher/src/com/android/car/carlauncher/CarLauncher.java
--- a/src/com/android/car/carlauncher/CarLauncher.java
+++ b/src/com/android/car/carlauncher/CarLauncher.java
@@ -21,7 +21,10 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERL
import android.app.ActivityManager;
import android.app.TaskStackListener;
+import android.melon.MelonManager;
+import android.melon.Person;
import android.car.user.CarUserManager;
+import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
@@ -108,6 +111,13 @@ public class CarLauncher extends FragmentActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ MelonManager melonManager = (MelonManager) getSystemService(Context.MELON_SERVICE);
+ melonManager.sayHello("Hello world !");
+ Person person = new Person();
+ person.setName("Rick");
+ person.setAge(32);
+ melonManager.sayHelloTo(person, " Good Night!!!");
+
if (CarLauncherUtils.isCustomDisplayPolicyDefined(this)) {
Intent controlBarIntent = new Intent(this, ControlBarActivity.class);
controlBarIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ここを呼び出すときは、別の selinux 権限を追加する必要があります。クライアントごとに異なるルールを追加する必要がある場合があります。実際のビジネス ニーズに応じてここにルールを追加できます。
ここでは CarLauncher が platform_app に属しているため、以下を追加します。
// vendor/zzh/sepolicy/public/platform_app.te
allow platform_app melonserver_service:service_manager find;
通常の動作ログは以下のとおりです。
04-12 22:24:19.342 641 670 I ActivityManager: Start proc 993:com.zzh.melonservice/1000 for added application com.zzh.melonservice
04-12 22:24:19.343 641 641 D SystemServerTiming: StartMelonManagerService
04-12 22:24:19.343 641 641 V SystemServerTiming: StartMelonManagerService took to complete: 0ms
04-12 22:24:19.602 993 993 D MelonApplication: onCreate
04-12 22:24:19.602 993 993 D MelonManagerService: MelonManagerService
04-12 22:24:19.725 641 1086 V StorageManagerService: Package com.zzh.melonservice has legacy storage
04-12 22:24:28.645 1960 1960 D MelonManager: new MelonManager
04-12 22:24:28.645 1960 1960 D MelonManager: sayHello words: Hello world !
04-12 22:24:28.646 993 1046 D MelonManagerService: sayHello : Hello world !
04-12 22:24:28.646 1960 1960 D MelonManager: sayHelloTo Rick: Good Night!!!
04-12 22:24:28.648 993 1024 D MelonManagerService: sayHello Rick: Good Night!!!