Android 13 Java调用Native本地服务

文章目录

  • 1. AIDL生成Java接口
  • 2. 添加Manager
    • 添加Java接口的服务名称
    • 定义XXXManager类
  • 3. java 客户端访问Nativie服务
    • Client调用
    • Selinux配置
    • 编译验证

欢迎关注微信公众号 无限无羡

前面有写过如何添加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文件添加编译生成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",
    ],
}

2. 添加Manager

我们知道,系统服务都是通过XXXManager类(比如:ActivityManager, PackageManager等)给App访问系统服务的,XXXManager就是对Binder服务代理的封装,我们这里命名为BeanManager,并进行定义。

添加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 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

定义XXXManager类

// 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

3. java 客户端访问Nativie服务

为了方便,我们就不编写新的Java程序了,我们在CarLauncher启动的时候去获取BeanManager对象,然后调用sayHello接口

Client调用

// 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配置

直接编译运行的话报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

Android 13 Java调用Native本地服务_第1张图片
一切运行正常,完。

你可能感兴趣的:(android,java,python)