前面有写过如何添加Native服务的一篇文章(Android 13添加自定义native服务),但是那篇文章最后只写了c++通过binder调用Native服务的例子,本篇博客补充一下Java语言的Client如何通过Binder调用Native服务。
在前面的博客中,经编译后,aidl文件默认生成的是C++类型的Binder类接口,原因是aidl是包含在c++的编译选项里,如下:
// vendor/zzh/native-service/bean-server/libbeanservice/Android.bp
// 这个标签是编译so库的
cc_library_shared {
name: "libbeanservice_aidl",
aidl: {
export_aidl_headers: true,
local_include_dirs: ["aidl"],
include_dirs: [
],
},
// 编译的源文件 beanservice_aidl
srcs: [
":beanservice_aidl",
],
shared_libs: [
"libbase",
"libcutils",
"libutils",
"liblog",
"libbinder",
"libgui",
],
cflags: [
"-Werror",
"-Wall",
"-Wextra",
],
}
filegroup {
// 该模块被上面引用
name: "beanservice_aidl",
// aidl接口文件,由于最后是编译c++时引用,所以只生成c++ binder类
srcs: [
"aidl/com/zzh/IBeanService.aidl",
],
path: "aidl",
}
如果要生产java binder类的话,就需要把beanservice_aidl包含到Java编译的Android.bp中,如下:
// android-13.0.0_r30/frameworks/base/Android.bp
// 这里是系统原生里将系统服务的aidl文件添加编译生成java binder类的地方,所以我们也加到这里,当然也可以自己写一个编译Java
// 的Android.bp,将beanservice_aidl添加进去
filegroup {
name: "framework-non-updatable-sources",
srcs: [
// Java/AIDL sources under frameworks/base
":framework-annotations",
":framework-blobstore-sources",
":framework-core-sources",
":framework-drm-sources",
":framework-graphics-nonupdatable-sources",
":framework-jobscheduler-sources", // jobscheduler is not a module for R
":framework-keystore-sources",
":framework-identity-sources",
":framework-location-sources",
":framework-lowpan-sources",
":framework-mca-effect-sources",
":framework-mca-filterfw-sources",
":framework-mca-filterpacks-sources",
":framework-media-non-updatable-sources",
":framework-mms-sources",
":framework-omapi-sources",
":framework-opengl-sources",
":framework-rs-sources",
":framework-sax-sources",
":framework-telecomm-sources",
":framework-telephony-common-sources",
":framework-telephony-sources",
":framework-vcn-util-sources",
":framework-wifi-annotations",
":framework-wifi-non-updatable-sources",
":PacProcessor-aidl-sources",
":ProxyHandler-aidl-sources",
":net-utils-framework-common-srcs",
// AIDL from frameworks/base/native/
":platform-compat-native-aidl",
// AIDL sources from external directories
":android.hardware.gnss-V2-java-source",
":android.hardware.graphics.common-V3-java-source",
":android.hardware.security.keymint-V2-java-source",
":android.hardware.security.secureclock-V1-java-source",
":android.hardware.tv.tuner-V1-java-source",
":android.security.apc-java-source",
":android.security.authorization-java-source",
":android.security.legacykeystore-java-source",
":android.security.maintenance-java-source",
":android.security.metrics-java-source",
":android.system.keystore2-V1-java-source",
":credstore_aidl",
":dumpstate_aidl",
":framework_native_aidl",
":gatekeeper_aidl",
":gsiservice_aidl",
":guiconstants_aidl",
":idmap2_aidl",
":idmap2_core_aidl",
":incidentcompanion_aidl",
":inputconstants_aidl",
":installd_aidl",
":libaudioclient_aidl",
":libbinder_aidl",
// 这里是CameraServer aidl文件编译添加的地方,CameraServer就是一个native服务,但是可以被App通过Java调用
":libcamera_client_aidl",
// 这里是我们自定义的服务添加aidl编译的地方,这里加上后,镜像编译完成后就会生成java的binder类,java就可以通过
// binder接口访问这个native服务了
":beanservice_aidl",
":libcamera_client_framework_aidl",
":libupdate_engine_aidl",
":logd_aidl",
":resourcemanager_aidl",
":storaged_aidl",
":vold_aidl",
":deviceproductinfoconstants_aidl",
// For the generated R.java and Manifest.java
":framework-res{.aapt.srcjar}",
// etc.
":framework-javastream-protos",
":statslog-framework-java-gen", // FrameworkStatsLog.java
":audio_policy_configuration_V7_0",
],
}
我们知道,系统服务都是通过XXXManager类(比如:ActivityManager, PackageManager等)给App访问系统服务的,XXXManager就是对Binder服务代理的封装,我们这里命名为BeanManager,并进行定义。
// 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 fce23cf6819a..4d83a6a2ebe6 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,
@@ -4277,6 +4278,16 @@ public abstract class Context {
*/
public static final String ALARM_SERVICE = "alarm";
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.app.AlarmManager} for receiving intents at a
+ * time of your choosing.
+ *
+ * @see #getSystemService(String)
+ * @see android.app.BeanManager
+ */
+ public static final String BEAN_SERVICE = "bean";
+
/**
* Use with {@link #getSystemService(String)} to retrieve a
* {@link android.app.NotificationManager} for informing the user of
添加到SystemServiceRegistry的管理中,这样就可以通过Context的getSystemService(Context.BEAN_SERVICE)
拿到BeanManager对象了。
// 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 b6189692107e..60ae23beab4c 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -245,6 +245,8 @@ import com.android.internal.os.IDropBoxManagerService;
import com.android.internal.policy.PhoneLayoutInflater;
import com.android.internal.util.Preconditions;
+import android.bean.BeanManager;
+
import java.util.Map;
import java.util.Objects;
@@ -808,6 +810,13 @@ public final class SystemServiceRegistry {
return new AppOpsManager(ctx, service);
}});
+ registerService(Context.BEAN_SERVICE, BeanManager.class,
+ new CachedServiceFetcher<BeanManager>() {
+ @Override
+ public BeanManager createService(ContextImpl ctx) {
+ return new BeanManager(ctx);
+ }});
+
registerService(Context.CAMERA_SERVICE, CameraManager.class,
new CachedServiceFetcher<CameraManager>() {
@Override
// frameworks/base/core/java/android/bean/BeanManager.java
// 我们新建了一个bean目录用来保存我们的BeanManager类,对应的包名为
// android.bean
package android.bean;
import android.annotation.NonNull;
import android.annotation.SystemService;
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import com.zzh.IBeanService;
@SystemService(Context.BEAN_SERVICE)
public class BeanManager {
private static final String TAG = "BeanManager";
// 这个名称是Native服务注册到ServiceManager中的名称,这个代理类将会调用
// Java的ServiceManager的getService得到binder代理
private static final String BEAN_SERVICE_BINDER_NAME = "bean.like";
private Context mContext;
/**
* @hide
*/
public BeanManager(Context ctx) {
Log.d(TAG, "new BeanManager");
mContext = ctx;
}
public void sayHello() {
Log.d(TAG, "sayHello ");
// 通过内部类BeanManagerGlobal获取代理对象
IBeanService beanService = BeanManagerGlobal.get().getBeanService();
if (beanService == null) {
Log.d(TAG, "sayHello beanService is null!!!");
return;
}
try {
// 通过代理对象调用服务函数
beanService.sayHello();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
// 内部类,获取服务端binder代理,封装对native服务的调用,是一个单利
private static final class BeanManagerGlobal implements IBinder.DeathRecipient {
private IBeanService mBeanService;
private static final BeanManagerGlobal gBeanManager =
new BeanManagerGlobal();
private BeanManagerGlobal() { }
public static BeanManagerGlobal get() {
return gBeanManager;
}
public void binderDied() {
mBeanService = null;
}
// 获取服务binder代理
public IBeanService getBeanService() {
connectBeanServiceLocked();
if (mBeanService == null) {
Log.e(TAG, "Bean service is unavailable");
}
return mBeanService;
}
private void connectBeanServiceLocked() {
// Only reconnect if necessary
if (mBeanService != null)
return;
Log.i(TAG, "Connecting to bean service");
// 通过ServiceManager对象拿到服务代理
IBinder beanServiceBinder = ServiceManager.getService(BEAN_SERVICE_BINDER_NAME);
if (beanServiceBinder == null) {
// Bean service is now down, leave mService as null
return;
}
try {
beanServiceBinder.linkToDeath(this, /* flags */ 0);
} catch (RemoteException e) {
// Bamera service is now down, leave mService as null
return;
}
// 拿到代理对象,后续对服务收到操作都是通过这里拿到的mBeanService代理对象
mBeanService = IBeanService.Stub.asInterface(beanServiceBinder);
}
}
}
上面添加完成后,基本就完成了对java接口的封装了,但是编译时会有如下问题:
352 Error: out/soong/.intermediates/frameworks/base/framework-minus-apex/android_common/aligned/framework-minus-apex.jar contains class file com.zzh.IBeanService, whose package name "com.zzh " is empty or not in the allow list build/soong/scripts/check_boot_jars/package_allowed_list.txt of packages allowed on the bootclasspath.
根据提示,将com.zzh添加如下文件就可以了
// build/soong/scripts/check_boot_jars/package_allowed_list.txt
diff --git a/scripts/check_boot_jars/package_allowed_list.txt b/scripts/check_boot_jars/package_allowed_list.txt
index a02c19560..d5e61d763 100644
--- a/scripts/check_boot_jars/package_allowed_list.txt
+++ b/scripts/check_boot_jars/package_allowed_list.txt
@@ -91,6 +91,7 @@ sun\.reflect.*
sun\.nio.*
sun\.net.*
com\.sun\..*
+com\.zzh.*
# TODO: Move these internal org.apache.harmony classes to libcore.*
org\.apache\.harmony\.crypto\.internal
为了方便,我们就不编写新的Java程序了,我们在CarLauncher启动的时候去获取BeanManager对象,然后调用sayHello接口
// packages/apps/Car/Launcher/src/com/android/car/carlauncher/CarLauncher.java
diff --git a/src/com/android/car/carlauncher/CarLauncher.java b/src/com/android/car/carlauncher/CarLauncher.java
index aa799ef..14a7651 100644
--- a/src/com/android/car/carlauncher/CarLauncher.java
+++ b/src/com/android/car/carlauncher/CarLauncher.java
@@ -21,9 +21,11 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERL
import android.app.ActivityManager;
import android.app.TaskStackListener;
+import android.bean.BeanManager;
import android.car.user.CarUserManager;
import android.content.Intent;
import android.content.res.Configuration;
+import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.ViewGroup;
@@ -108,6 +110,8 @@ public class CarLauncher extends FragmentActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ BeanManager beanManager = (BeanManager) getSystemService(Context.BEAN_SERVICE);
+ beanManager.sayHello();
if (CarLauncherUtils.isCustomDisplayPolicyDefined(this)) {
Intent controlBarIntent = new Intent(this, ControlBarActivity.class);
controlBarIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
直接编译运行的话报Selinux权限问题,所以要配置相应权限,因为CarLauncher是platform_app,所以我们对这个类型进行添加,添加权限的目录参考上篇文章(Android 13添加自定义native服务),在之前基础上要修改两个地方:
// 新建vendor/zzh/sepolicy/public/beanserver.te文件
type beanserver, domain, coredomain;
type beanserver_exec, exec_type, file_type, system_file_type;
// 上面两行的内容原来在vendor/beanserver.te中,将这段内容从vendor/beanserver.te删除,
// 因为后面会用到type beanserver和type beanserver_exec,必须放在public目录。
// 下面这一行是新加的,必须添加,否则Client无法通过binder调用服务端aidl里的接口函数
binder_service(beanserver)
// 添加vendor/zzh/sepolicy/vendor/platform_app.te文件
allow platform_app beanserver_service:service_manager find;
由于添加了新的api,所以要先更新api
source build/envsetup.sh
lunch sdk_car_x86_64-userdebug
make update-api -j16
make -j16
编译完成后启动模拟器
emulator
另起动一个窗口查看日志:
adb logcat|grep -i bean