欢迎重视微信大众号 无限无羡

前面有写过怎么增加Native服务的一篇文章(Android 13增加自界说native服务),可是那篇文章最终只写了c++经过binder调用Native服务的例子,本篇博客补充一下Java言语的Client怎么经过Binder调用Native服务。

1. AIDL生成Java接口

在前面的博客中,经编译后,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文件增加编译生成javabinder类的当地,所以咱们也加到这儿,当然也能够自己写一个编译Java
//的Android.bp,将beanservice_aidl增加进去
filegroup{
name:"framework-non-updatable-sources",
srcs:[
//Java/AIDLsourcesunderframeworks/base
":framework-annotations",
":framework-blobstore-sources",
":framework-core-sources",
":framework-drm-sources",
":framework-graphics-nonupdatable-sources",
":framework-jobscheduler-sources",//jobschedulerisnotamoduleforR
":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",
//AIDLfromframeworks/base/native/
":platform-compat-native-aidl",
//AIDLsourcesfromexternaldirectories
":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",
//这儿是CameraServeraidl文件编译增加的当地,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",
//ForthegeneratedR.javaandManifest.java
":framework-res{.aapt.srcjar}",
//etc.
":framework-javastream-protos",
":statslog-framework-java-gen",//FrameworkStatsLog.java
":audio_policy_configuration_V7_0",
],
}

2. 增加Manager

咱们知道,体系服务都是经过XXXManager类(比如:ActivityManager, PackageManager等)给App拜访体系服务的,XXXManager便是对Binder服务署理的封装,咱们这儿命名为BeanManager,并进行界说。

增加Java接口的服务称号

//frameworks/base/core/java/android/content/Context.java
diff--gita/core/java/android/content/Context.javab/core/java/android/content/Context.java
indexfce23cf6819a..4d83a6a2ebe6100644
---a/core/java/android/content/Context.java
+++b/core/java/android/content/Context.java
@@-3809,6+3809,7@@publicabstractclassContext{
ACCOUNT_SERVICE,
ACTIVITY_SERVICE,
ALARM_SERVICE,
+BEAN_SERVICE,
NOTIFICATION_SERVICE,
ACCESSIBILITY_SERVICE,
CAPTIONING_SERVICE,
@@-4277,6+4278,16@@publicabstractclassContext{
*/
publicstaticfinalStringALARM_SERVICE="alarm";
+/**
+*Usewith{@link#getSystemService(String)}toretrievea
+*{@linkandroid.app.AlarmManager}forreceivingintentsata
+*timeofyourchoosing.
+*
+*@see#getSystemService(String)
+*@seeandroid.app.BeanManager
+*/
+publicstaticfinalStringBEAN_SERVICE="bean";
+
/**
*Usewith{@link#getSystemService(String)}toretrievea
*{@linkandroid.app.NotificationManager}forinformingtheuserof

增加到SystemServiceRegistry的办理中,这样就能够经过Context的getSystemService(Context.BEAN_SERVICE)
拿到BeanManager目标了。

//frameworks/base/core/java/android/app/SystemServiceRegistry.java
diff--gita/core/java/android/app/SystemServiceRegistry.javab/core/java/android/app/SystemServiceRegistry.java
indexb6189692107e..60ae23beab4c100644
---a/core/java/android/app/SystemServiceRegistry.java
+++b/core/java/android/app/SystemServiceRegistry.java
@@-245,6+245,8@@importcom.android.internal.os.IDropBoxManagerService;
importcom.android.internal.policy.PhoneLayoutInflater;
importcom.android.internal.util.Preconditions;
+importandroid.bean.BeanManager;
+
importjava.util.Map;
importjava.util.Objects;
@@-808,6+810,13@@publicfinalclassSystemServiceRegistry{
returnnewAppOpsManager(ctx,service);
}});
+registerService(Context.BEAN_SERVICE,BeanManager.class,
+newCachedServiceFetcher<BeanManager>(){
+@Override
+publicBeanManagercreateService(ContextImplctx){
+returnnewBeanManager(ctx);
+}});
+
registerService(Context.CAMERA_SERVICE,CameraManager.class,
newCachedServiceFetcher<CameraManager>(){
@Override

界说XXXManager类

//frameworks/base/core/java/android/bean/BeanManager.java
//咱们新建了一个bean目录用来保存咱们的BeanManager类,对应的包名为
//android.bean
packageandroid.bean;
importandroid.annotation.NonNull;
importandroid.annotation.SystemService;
importandroid.content.Context;
importandroid.os.IBinder;
importandroid.os.RemoteException;
importandroid.os.ServiceManager;
importandroid.util.Log;
importcom.zzh.IBeanService;
@SystemService(Context.BEAN_SERVICE)
publicclassBeanManager{
privatestaticfinalStringTAG="BeanManager";
//这个称号是Native服务注册到ServiceManager中的称号,这个署理类将会调用
//Java的ServiceManager的getService得到binder署理
privatestaticfinalStringBEAN_SERVICE_BINDER_NAME="bean.like";
privateContextmContext;
/**
*@hide
*/
publicBeanManager(Contextctx){
Log.d(TAG,"newBeanManager");
mContext=ctx;
}
publicvoidsayHello(){
Log.d(TAG,"sayHello");
//经过内部类BeanManagerGlobal获取署理目标
IBeanServicebeanService=BeanManagerGlobal.get().getBeanService();
if(beanService==null){
Log.d(TAG,"sayHellobeanServiceisnull!!!");
return;
}
try{
//经过署理目标调用服务函数
beanService.sayHello();
}catch(RemoteExceptione){
throwe.rethrowFromSystemServer();
}
}
//内部类,获取服务端binder署理,封装对native服务的调用,是一个单利
privatestaticfinalclassBeanManagerGlobalimplementsIBinder.DeathRecipient{
privateIBeanServicemBeanService;
privatestaticfinalBeanManagerGlobalgBeanManager=
newBeanManagerGlobal();
privateBeanManagerGlobal(){}
publicstaticBeanManagerGlobalget(){
returngBeanManager;
}
publicvoidbinderDied(){
mBeanService=null;
}
//获取服务binder署理
publicIBeanServicegetBeanService(){
connectBeanServiceLocked();
if(mBeanService==null){
Log.e(TAG,"Beanserviceisunavailable");
}
returnmBeanService;
}
privatevoidconnectBeanServiceLocked(){
//Onlyreconnectifnecessary
if(mBeanService!=null)
return;
Log.i(TAG,"Connectingtobeanservice");
//经过ServiceManager目标拿到服务署理
IBinderbeanServiceBinder=ServiceManager.getService(BEAN_SERVICE_BINDER_NAME);
if(beanServiceBinder==null){
//Beanserviceisnowdown,leavemServiceasnull
return;
}
try{
beanServiceBinder.linkToDeath(this,/*flags*/0);
}catch(RemoteExceptione){
//Bameraserviceisnowdown,leavemServiceasnull
return;
}
//拿到署理目标,后续对服务收到操作都是经过这儿拿到的mBeanService署理目标
mBeanService=IBeanService.Stub.asInterface(beanServiceBinder);
}
}
}

上面增加完成后,基本就完成了对java接口的封装了,可是编译时会有如下问题:

352Error:out/soong/.intermediates/frameworks/base/framework-minus-apex/android_common/aligned/framework-minus-apex.jarcontainsclassfilecom.zzh.IBeanService,whosepackagename"com.zzh"isemptyornotintheallowlistbuild/soong/scripts/check_boot_jars/package_allowed_list.txtofpackagesallowedonthebootclasspath.

依据提示,将com.zzh增加如下文件就能够了

//build/soong/scripts/check_boot_jars/package_allowed_list.txt
diff--gita/scripts/check_boot_jars/package_allowed_list.txtb/scripts/check_boot_jars/package_allowed_list.txt
indexa02c19560..d5e61d763100644
---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:Movetheseinternalorg.apache.harmonyclassestolibcore.*
org.apache.harmony.crypto.internal

3. java 客户端拜访Nativie服务

为了方便,咱们就不编写新的Java程序了,咱们在CarLauncher发动的时分去获取BeanManager目标,然后调用sayHello接口

Client调用

//packages/apps/Car/Launcher/src/com/android/car/carlauncher/CarLauncher.java
diff--gita/src/com/android/car/carlauncher/CarLauncher.javab/src/com/android/car/carlauncher/CarLauncher.java
indexaa799ef..14a7651100644
---a/src/com/android/car/carlauncher/CarLauncher.java
+++b/src/com/android/car/carlauncher/CarLauncher.java
@@-21,9+21,11@@importstaticandroid.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERL
importandroid.app.ActivityManager;
importandroid.app.TaskStackListener;
+importandroid.bean.BeanManager;
importandroid.car.user.CarUserManager;
importandroid.content.Intent;
importandroid.content.res.Configuration;
+importandroid.content.Context;
importandroid.os.Bundle;
importandroid.util.Log;
importandroid.view.ViewGroup;
@@-108,6+110,8@@publicclassCarLauncherextendsFragmentActivity{
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
+BeanManagerbeanManager=(BeanManager)getSystemService(Context.BEAN_SERVICE);
+beanManager.sayHello();
if(CarLauncherUtils.isCustomDisplayPolicyDefined(this)){
IntentcontrolBarIntent=newIntent(this,ControlBarActivity.class);
controlBarIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Selinux装备

直接编译运转的话报Selinux权限问题,所以要装备相应权限,由于CarLauncher是platform_app,所以咱们对这个类型进行增加,增加权限的目录参考上篇文章(Android 13增加自界说native服务),在之前基础上要修正两个当地:

//新建vendor/zzh/sepolicy/public/beanserver.te文件
typebeanserver,domain,coredomain;
typebeanserver_exec,exec_type,file_type,system_file_type;
//上面两行的内容本来在vendor/beanserver.te中,将这段内容从vendor/beanserver.te删去,
//由于后边会用到typebeanserver和typebeanserver_exec,必须放在public目录。
//下面这一行是新加的,必须增加,否则Client无法经过binder调用服务端aidl里的接口函数
binder_service(beanserver)
//增加vendor/zzh/sepolicy/vendor/platform_app.te文件
allowplatform_appbeanserver_service:service_managerfind;

编译验证

由于增加了新的api,所以要先更新api

sourcebuild/envsetup.sh
lunchsdk_car_x86_64-userdebug
makeupdate-api-j16
make-j16
编译完成后发动模拟器
emulator
另起动一个窗口检查日志:
adblogcat|grep-ibean

Android 13 Java调用Native本地服务

在这儿刺进图片描绘

一切运转正常,完。