赞
踩
欢迎加入我的知识星球Android系统开发指南
本节先介绍第一种方法,下一节介绍第二种方法。
我们将自定义的服务取名为BeanManagerService。
Binder默认可以传输基本类型的数据,如果要传递类对象,则这个类需要实现序列化。我们先定义一个序列化的自定义类型,用于binder间参数传递。主要分为两步:
// frameworks/base/core/java/android/bean/Person.java package android.bean; 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/bean/Person.aidl
package android.bean;
parcelable Person;
这样就定义好了一个自定义对象类型,该类型可以通过binder传递,下面我们会有例子说明。
接下来我们定义自定义服务,首先要定义一个aidl文件来定义我们的接口,这个aidl文件编译后会生成binder的客户端服务端接口,我们需要实现客户端和服务端。
// bean为新建的文件夹,用于存放自定义服务 // frameworks/base/core/java/android/bean/IBeanManager.aidl package android.bean; import android.bean.Person; /** * {@hide} */ interface IBeanManager { void sayHello(String words); // 自定义类型前面必须加上in或者out或者inout标识符 // in: 表示参数只能由客户端传递到服务端,基本类型默认只支持in修饰符 // out: 表示参数只能由服务端传递到客户端,服务端如果修改了参数对象的值 // 那么客户端的值也会改变,但是服务端无法读取客户端对象的值 // inout: 表示参数可以双向传递 void sayHelloTo(in Person person, String words); }
由于下面的Android.bp已经包含了该目录下几乎所有aidl文件和java文件的编译,所以我们不需要再将自定义的BeanManager.aidl添加到编译环境。
// frameworks/base/core/java/Android.bp filegroup { name: "framework-core-sources", srcs: [ "**/*.java", "**/*.aidl", ], exclude_srcs: [ // Remove election toolbar code from build time "android/service/selectiontoolbar/*.aidl", "android/service/selectiontoolbar/*.java", "android/view/selectiontoolbar/*.aidl", "android/view/selectiontoolbar/*.java", "com/android/internal/widget/floatingtoolbar/RemoteFloatingToolbarPopup.java", ], visibility: ["//frameworks/base"], }
用以下命令编译aidl
source build/envsetup.sh
lunch sdk_car_x86_64-userdebug// 这里选择自己的项目
make update-api
make framework -j16
编译完成后,可以看到out下已经生成了binder相关的文件
cd frameworks/base
mkdir -p services/core/java/com/android/server/bean/
新建BeanManagerService.java
编译配置同上,不需要再单独加到编译配置中。
// frameworks/base/services/core/java/com/android/server/bean/BeanManagerService.java package com.android.server.bean; import android.bean.IBeanManager; import android.bean.Person; import android.content.Context; import android.util.Log; import com.android.server.SystemService; import com.android.server.Watchdog; public class BeanManagerService extends IBeanManager.Stub implements Watchdog.Monitor { static final String TAG = "BeanManagerService"; final Context mContext; public BeanManagerService(Context systemContext) { Log.d(TAG, "BeanManagerService"); mContext = systemContext; Watchdog.getInstance().addMonitor(this); } @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); } public void systemReady() { Log.d(TAG, " systemReady "); } /** In this method we try to acquire our lock to make sure that we have not deadlocked */ public void monitor() { synchronized (this) { } } // 这里我们定义了一个内部类继承SystemService,这样便于方便system_server统一管理启动服务 // 系统启动时会回调所有继承了SystemService的类的函数,比如onStart,onBootPhase等等。 public static final class Lifecycle extends SystemService { static final String TAG = "BeanManagerService.Lifecycle"; private BeanManagerService mService; public Lifecycle(Context context) { super(context); // 在这里构造我们的BeanManagerService对象 mService = new BeanManagerService(context); } @Override public void onStart() { Log.d(TAG, "onStart"); // 这里最终调用ServiceManager.addService publishBinderService(Context.BEAN_SERVICE, mService); } @Override public void onBootPhase(int phase) { Log.d(TAG, "onBootPhase"); if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { mService.systemReady(); } } } }
添加服务名称
// 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 77ca48a8ed1d..6ad91d26daf7 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3809,6 +3809,7 @@ public abstract class Context { ACCOUNT_SERVICE, ACTIVITY_SERVICE, ALARM_SERVICE, + BEAN_SERVICE, NOTIFICATION_SERVICE, ACCESSIBILITY_SERVICE, CAPTIONING_SERVICE, @@ -4248,6 +4249,16 @@ public abstract class Context { */ public static final String ACTIVITY_SERVICE = "activity"; + /** + * Use with {@link #getSystemService(String)} to retrieve a + * {@link android.bean.BeanManager} for interacting with the global + * system state. + * + * @see #getSystemService(String) + * @see android.bean.BeanManager + */ + public static final String BEAN_SERVICE = "bean"; +
开机启动服务:
// frameworks/base/services/java/com/android/server/SystemServer.java // 系统启动时将服务分为几个类型,如下,我们可以根据自己的具体业务添加到对应的函数里面 try { t.traceBegin("StartServices"); // 引导服务,必须 startBootstrapServices(t); // 核心服务,必须 startCoreServices(t); // 其他服务,一般放在这里面 startOtherServices(t); // 定义在apexes中的服务apexes,有兴趣的可以看下源码 startApexServices(t); } catch (Throwable ex) { Slog.e("System", "******************************************"); Slog.e("System", "************ Failure starting system services", ex); throw ex; } finally { t.traceEnd(); // StartServices } --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -110,6 +110,7 @@ import com.android.server.appbinding.AppBindingService; import com.android.server.art.ArtManagerLocal; import com.android.server.attention.AttentionManagerService; import com.android.server.audio.AudioService; +import com.android.server.bean.BeanManagerService; import com.android.server.biometrics.AuthService; import com.android.server.biometrics.BiometricService; import com.android.server.biometrics.sensors.face.FaceService; @@ -1466,6 +1467,10 @@ public final class SystemServer implements Dumpable { } }, SECONDARY_ZYGOTE_PRELOAD); + t.traceBegin("BeanManagerService"); // 这里最终会通过反射的方法调用BeanManagerService.Lifecycle的构造函数 + mSystemServiceManager.startService(BeanManagerService.Lifecycle.class); + t.traceEnd(); + t.traceBegin("StartKeyAttestationApplicationIdProviderService"); ServiceManager.addService("sec_key_att_app_id_provider", new KeyAttestationApplicationIdProviderService(context));
mSystemServiceManager.startService的实现:
// frameworks/base/services/core/java/com/android/server/SystemServiceManager.java public <T extends SystemService> T startService(Class<T> serviceClass) { try { final String name = serviceClass.getName(); Slog.i(TAG, "Starting " + name); Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name); // Create the service. if (!SystemService.class.isAssignableFrom(serviceClass)) { throw new RuntimeException("Failed to create " + name + ": service must extend " + SystemService.class.getName()); } final T service; try { // 调用构造函数,对于我们的自定义服务就是BeanManagerService.Lifecycle Constructor<T> constructor = serviceClass.getConstructor(Context.class); service = constructor.newInstance(mContext); } catch (InstantiationException ex) { throw new RuntimeException("Failed to create service " + name + ": service could not be instantiated", ex); } catch (IllegalAccessException ex) { throw new RuntimeException("Failed to create service " + name + ": service must have a public constructor with a Context argument", ex); } catch (NoSuchMethodException ex) { throw new RuntimeException("Failed to create service " + name + ": service must have a public constructor with a Context argument", ex); } catch (InvocationTargetException ex) { throw new RuntimeException("Failed to create service " + name + ": service constructor threw an exception", ex); } startService(service); return service; } finally { Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); } } public void startService(@NonNull final SystemService service) { // Check if already started String className = service.getClass().getName(); if (mServiceClassnames.contains(className)) { Slog.i(TAG, "Not starting an already started service " + className); return; } mServiceClassnames.add(className); // 将BeanManagerService.Lifecycle加入mServices列表 // 系统的启动过程会遍历mServices列表,回调每个服务的对应函数 // Register it. mServices.add(service); // Start it. long time = SystemClock.elapsedRealtime(); try { // 这里就是调用每个服务的onStart函数 service.onStart(); } catch (RuntimeException ex) { throw new RuntimeException("Failed to start service " + service.getClass().getName() + ": onStart threw an exception", ex); } warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart"); }
到此,服务的添加代码已经完成,我们编译验证一下:
// 因为Context.java中新增了BEAN_SERVICE的API,所以要先make update-api
source build/envsetup.sh
lunch sdk_car_x86_64-userdebug
make update-api -j16
make -j16
启动模拟器
emulator
这时发现服务无法启动,看日志有如下报错:
Selinux权限问题,我们根据日志按规则添加:
adb pull /sys/fs/selinux/policy
adb logcat -b events -d | audit2allow -p policy
输出信息如下:
#============= system_server ==============
allow system_server default_android_service:service_manager add;
大家如果看过我的另一篇文章Android 13添加自定义native服务,就能立马明白这里该如何添加。
如果按照上面的提示应该是在system_server.te里添加allow system_server default_android_service:service_manager add;
但是这样会触发neverallow,正确的方法是为自定义的服务添加一个新的标签:
// vendor/zzh/sepolicy/private/service_contexts
bean u:object_r:bean_service:s0
// vendor/zzh/sepolicy/public/service.te
type bean_service, service_manager_type;
// vendor/zzh/sepolicy/public/system_server.te
allow system_server bean_service:service_manager add;
上述修改的文件大家根据自己项目添加到具体的文件中,也可以参考Android 13添加自定义native服务。
修改后重新编译启动验证
可以看到服务已经正常启动。
如果遇到修改selinux后开机还是报错的情况,手动kill掉模拟器进程再启动模拟器。
Client调用实际上就是获取binder的代理对象,然后通过代理对象调用服务端的方法。在Android系统中,为了方便App使用系统服务的功能,一般都会给每个服务定义一个XXXManager,App可以通过Context.getSystemService(serviceName)来获取到经过包装的服务端的代理XXXManager。Context.getSystemService最终会调用到SystemServiceRegistry中的getSystemService。
// frameworks/base/core/java/android/app/SystemServiceRegistry.java /** * Gets a system service from a given context. * @hide */ public static Object getSystemService(ContextImpl ctx, String name) { if (name == null) { return null; } // SYSTEM_SERVICE_FETCHERS是一个map,保存了每个服务的名称和Manager的映射关系 // ServiceFetcher是一个接口,有一个抽象方法T getService(ContextImpl ctx); // 这个getService返回的便是服务的代理包装类XXXManager final ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name); if (fetcher == null) { if (sEnableServiceNotFoundWtf) { Slog.wtf(TAG, "Unknown manager requested: " + name); } return null; } final Object ret = fetcher.getService(ctx); if (sEnableServiceNotFoundWtf && ret == null) { // Some services do return null in certain situations, so don't do WTF for them. switch (name) { case Context.CONTENT_CAPTURE_MANAGER_SERVICE: case Context.APP_PREDICTION_SERVICE: case Context.INCREMENTAL_SERVICE: case Context.ETHERNET_SERVICE: return null; } Slog.wtf(TAG, "Manager wrapper not available: " + name); return null; } return ret; }
ServiceFetcher接口的定义
// frameworks/base/core/java/android/app/SystemServiceRegistry.java
/**
* Base interface for classes that fetch services.
* These objects must only be created during static initialization.
*/
static abstract interface ServiceFetcher<T> {
T getService(ContextImpl ctx);
}
ServiceFetcher接口的实现有两个,CachedServiceFetcher和StaticServiceFetcher,这两个其实是两个抽象类,都有一个抽象方法createService,而这个createService正式获取服务端代理的真正实现。CachedServiceFetcher顾名思义就是将每个服务的代理对象都进行缓存,下一次获取的时候直接使用缓存的对象就可以了。
// frameworks/base/core/java/android/app/SystemServiceRegistry.java /** * Override this class when the system service constructor needs a * ContextImpl and should be cached and retained by that context. */ static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> { private final int mCacheIndex; CachedServiceFetcher() { // Note this class must be instantiated only by the static initializer of the // outer class (SystemServiceRegistry), which already does the synchronization, // so bare access to sServiceCacheSize is okay here. // 每一个Context对象包含了一个保存服务代理的数组,每添加一个代理,也就是每创建一个CachedServiceFetcher, // sServiceCacheSize便会递增,而每个CachedServiceFetcher中的mCacheIndex则是自己在整个数组中的index。 // 后续获取服务代理时,如果cache中有数据,则直接根据mCacheIndex获取即可。 mCacheIndex = sServiceCacheSize++; } @Override @SuppressWarnings("unchecked") public final T getService(ContextImpl ctx) { //获取Context中的保存服务代理的数组mServiceCache final Object[] cache = ctx.mServiceCache; // final int[] mServiceInitializationStateArray = new int[mServiceCache.length]; // mServiceInitializationStateArray是一个以mServiceCache.length为size的int数组,用于 // 保存每个服务代理的状态,目前有四种状态: // static final int STATE_UNINITIALIZED = 0; // static final int STATE_INITIALIZING = 1; // static final int STATE_READY = 2; // static final int STATE_NOT_FOUND = 3; final int[] gates = ctx.mServiceInitializationStateArray; boolean interrupted = false; T ret = null; for (;;) { boolean doInitialize = false; synchronized (cache) { // Return it if we already have a cached instance. // 先根据mCacheIndex获取,如果不为null,说明之前已经保存过,直接返回。 T service = (T) cache[mCacheIndex]; if (service != null) { ret = service; break; // exit the for (;;) } // If we get here, there's no cached instance. // Grr... if gate is STATE_READY, then this means we initialized the service // once but someone cleared it. // We start over from STATE_UNINITIALIZED. // Similarly, if the previous attempt returned null, we'll retry again. // 走到这里说明缓存中没有保存代理对象 // 但是状态却是(STATE_READY),说明之前是添加过的,但是现在找不到了,说明被谁从数组中移除了 // 或者状态是找不到(STATE_NOT_FOUND) // 那么就将状态重置为STATE_UNINITIALIZED,重新再往cache数组添加一次 if (gates[mCacheIndex] == ContextImpl.STATE_READY || gates[mCacheIndex] == ContextImpl.STATE_NOT_FOUND) { gates[mCacheIndex] = ContextImpl.STATE_UNINITIALIZED; } // It's possible for multiple threads to get here at the same time, so // use the "gate" to make sure only the first thread will call createService(). // At this point, the gate must be either UNINITIALIZED or INITIALIZING. // 这里在往代理服务数组中添加新数据之前,先把状态设置为STATE_INITIALIZING if (gates[mCacheIndex] == ContextImpl.STATE_UNINITIALIZED) { doInitialize = true; gates[mCacheIndex] = ContextImpl.STATE_INITIALIZING; } } if (doInitialize) { // Only the first thread gets here. // 接下来就要真正的保存服务代理到数组中了 T service = null; @ServiceInitializationState int newState = ContextImpl.STATE_NOT_FOUND; try { // This thread is the first one to get here. Instantiate the service // *without* the cache lock held. // 这里通过createService获取到服务代理对象,前面说过createService是一个抽象方法, // 说明有子类实现的地方,后面会讲到 service = createService(ctx); newState = ContextImpl.STATE_READY; } catch (ServiceNotFoundException e) { onServiceNotFound(e); } finally { synchronized (cache) { //如果createService没有异常的话,将代理服务保存到cache数组 // 将状态设置为newState, newState在前面设置为了STATE_READY cache[mCacheIndex] = service; gates[mCacheIndex] = newState; cache.notifyAll(); } } ret = service; break; // exit the for (;;) } // The other threads will wait for the first thread to call notifyAll(), // and go back to the top and retry. synchronized (cache) { // Repeat until the state becomes STATE_READY or STATE_NOT_FOUND. // We can't respond to interrupts here; just like we can't in the "doInitialize" // path, so we remember the interrupt state here and re-interrupt later. // 如果服务代理正在添加过程中,还没有添加完成时,又有一个新的线程来getSystemService,则会 // 进去wait状态,等待服务代理对象添加完成后执行notifyAll来唤醒当前线程 while (gates[mCacheIndex] < ContextImpl.STATE_READY) { try { // Clear the interrupt state. interrupted |= Thread.interrupted(); cache.wait(); } catch (InterruptedException e) { // This shouldn't normally happen, but if someone interrupts the // thread, it will. Slog.w(TAG, "getService() interrupted"); interrupted = true; } } } } if (interrupted) { Thread.currentThread().interrupt(); } return ret; } // 抽象方法createService public abstract T createService(ContextImpl ctx) throws ServiceNotFoundException; } // StaticServiceFetcher则是服务代理中不需要Context对象的一种实现,也就是创建XXXManager对象时不需要 // 传入Context参数 /** * Override this class when the system service does not need a ContextImpl * and should be cached and retained process-wide. */ static abstract class StaticServiceFetcher<T> implements ServiceFetcher<T> { private T mCachedInstance; @Override public final T getService(ContextImpl ctx) { synchronized (StaticServiceFetcher.this) { if (mCachedInstance == null) { try { mCachedInstance = createService(); } catch (ServiceNotFoundException e) { onServiceNotFound(e); } } return mCachedInstance; } } public abstract T createService() throws ServiceNotFoundException; }
通过上面可以看到,CachedServiceFetcher和StaticServiceFetcher都需要实现createService的抽象方法,我们的自定义服务代理对象BeanManager假设需要传入Context对象,则需要使用CachedServiceFetcher。
// frameworks/base/core/java/android/app/SystemServiceRegistry.java registerService(Context.BEAN_SERVICE, BeanManager.class, // 这里是CachedServiceFetcher抽象类的实现 new CachedServiceFetcher<BeanManager>() { // 抽象方法createService的实现,我们看到其实很简单,就是通过ServiceManager获取服务的binder代理对象 @Override public BeanManager createService(ContextImpl ctx) throws ServiceNotFoundException { IBinder b = ServiceManager.getServiceOrThrow(Context.BEAN_SERVICE); IBeanManager service = IBeanManager.Stub.asInterface(b); // 以IBeanManager和Context为参数构造BeanManager,这样我们通过Context.getSysetemService(Context.BEAN_SERVICE) // 返回的对象就是BeanManager return new BeanManager(service, ctx); }}); /** * Statically registers a system service with the context. * This method must be called during static initialization only. */ // registerService只是保存为全局的对象 private static <T> void registerService(@NonNull String serviceName, @NonNull Class<T> serviceClass, @NonNull ServiceFetcher<T> serviceFetcher) { SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName); SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher); SYSTEM_SERVICE_CLASS_NAMES.put(serviceName, serviceClass.getSimpleName()); }
接下来就是该定义BeanManager了
// frameworks/base/core/java/android/bean/BeanManager.java package android.bean; import android.annotation.NonNull; import android.content.Context; import android.os.RemoteException; import android.util.Log; /** * {@hide} */ public class BeanManager { private static final String TAG = "BeanManager"; private Context mContext; private IBeanManager mService; public BeanManager(IBeanManager service, Context ctx) { Log.d(TAG, "new BeanManager"); 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, "sayHelloTo mService is null!!!"); return; } try { mService.sayHelloTo(person, words); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } }
到此,我们的服务代理就添加完成了。我们调用BeanManager测试一下,我们添加到Launcher里,开机加载
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.bean.BeanManager; +import android.bean.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); + BeanManager beanManager = (BeanManager) getSystemService(Context.BEAN_SERVICE); + beanManager.sayHello("Hello world !"); + Person person = new Person(); + person.setName("Rick"); + person.setAge(32); + beanManager.sayHelloTo(person, " Good Night!!!"); + if (CarLauncherUtils.isCustomDisplayPolicyDefined(this)) { Intent controlBarIntent = new Intent(this, ControlBarActivity.class); controlBarIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
编译后重启服务器,看到如下日志说明调用成功:
04-05 21:08:24.623 638 638 I SystemServiceManager: Starting com.android.server.bean.BeanManagerService$Lifecycle
04-05 21:08:24.624 638 638 D BeanManagerService: BeanManagerService
04-05 21:08:24.624 638 638 D BeanManagerService.Lifecycle: onStart
04-05 21:08:25.592 638 638 D BeanManagerService.Lifecycle: onBootPhase
04-05 21:08:25.650 638 638 D BeanManagerService.Lifecycle: onBootPhase
04-05 21:08:25.650 638 638 D BeanManagerService: systemReady
04-05 21:08:26.020 638 638 D BeanManagerService.Lifecycle: onBootPhase
04-05 21:08:36.513 1933 1933 D BeanManager: new BeanManager
04-05 21:08:36.513 1933 1933 D BeanManager: sayHello words: Hello world !
04-05 21:08:36.515 638 805 D BeanManagerService: sayHello : Hello world !
04-05 21:08:36.517 1933 1933 D BeanManager: sayHello to Rick: Good Night !
04-05 21:08:36.519 638 805 D BeanManagerService: sayHello to Rick: Good Night!
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。