Android 13 Java calls Native local services


Welcome to follow the WeChat public account Wuxian

I have written an article before about how to add a Native service ( Android 13 adds a custom native service ), but in the end that article only wrote an example of calling the Native service through binder in C++. This blog will add how to use the Java language Client Binder calls Native service.

1. AIDL generates Java interface

In the previous blog, after compilation, the aidl file generates a C++ type Binder class interface by default. The reason is that aidl is included in the c++ compilation option, as follows:

// 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",
}

If you want to produce a java binder class, you need to include beanservice_aidl into the Java compiled Android.bp, as follows:

// 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. Add Manager

We know that system services are accessed by the App through the XXXManager class (such as ActivityManager, PackageManager, etc.). XXXManager is the encapsulation of the Binder service agent. We name it BeanManager here and define it.

Add the service name of the Java interface

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

Add it to the management of SystemServiceRegistry, so that you can
get the BeanManager object through Context's getSystemService(Context.BEAN_SERVICE).

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

Define XXXManager class

// 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);
        }
    }

}

After the above additions are completed, the encapsulation of the Java interface is basically completed, but there will be the following problems during compilation:

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.

According to the prompts, just add the following file to 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 client accesses Nativie service

For convenience, we will not write a new Java program. We will obtain the BeanManager object when CarLauncher starts, and then call the sayHello interface.

Client call

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

If you directly compile and run, Selinux permissions will be reported, so you need to configure the corresponding permissions. Because CarLauncher is platform_app, we add this type. For the directory to add permissions, refer to the previous article (Android 13 adds custom native services), based on the previous There are two places to modify:

// 新建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;

Compilation verification

Since a new API has been added, the API must be updated first

source  build/envsetup.sh
lunch sdk_car_x86_64-userdebug
make update-api -j16
make -j16
编译完成后启动模拟器
emulator
另起动一个窗口查看日志:
adb logcat|grep -i bean

Insert image description here
Everything is running normally, done.

Guess you like

Origin blog.csdn.net/weixin_41678668/article/details/131484748