Android源码中添加JNI实战
前言
本文接着上一篇博文Android源码中添加AIDL服务实战,讲解如何在android源码中添加自己的JNI代码,并修改上一篇博文中自定义的服务,实现调用自己添加的JNI函数,最终在相机拍照时调用服务,验证JNI函数是否别正确调用。
JNI是java和C++两种语言直接沟通的桥梁,因为C++语言的优势,android源码中很多底层功能会使用C++实现,然后通过JNI让上层的java语言调用。这里不过多赘述,本篇博文和上一篇博文紧密联系,因此,建议阅读本篇文章前先阅读上篇博文:
Android源码中添加AIDL服务实战
一、添加JNI
1. 编写JNI代码
在frameworks/base/services/core/jni目录下添加com_android_server_HelloworldService.cpp
具体代码可以参考该目录下其它程序,结构比较固定,照葫芦画瓢就可以,主要包括以下三部分:
- 自定义的功能函数,后续要被上层调用
- 将自定义函数添加到数组static JNINativeMethod sMethods[]中
- 提供注册函数register_android_server_*,后续在onload.cpp中调用,具体实现很固定,可以参考其它程序,主要是jniRegisterNativeMethods函数调用
#define LOG_TAG "MyCustomService"
#include <nativehelper/JNIHelp.h>
#include "jni.h"
#include "android_runtime/AndroidRuntime.h"
#include "utils/misc.h"
#include "utils/Log.h"
#include "stdio.h"
namespace android{
// 实现加法功能函数,后续被自定义服务调用
static jint myCustom_AddVal(JNIEnv *env, jobject clazz, jint a, jint b) {
return a+b;
}
// 必须有的,注册函数到jni
static JNINativeMethod sMethods[] = {
{"addValue", "(II)I", (void *) myCustom_AddVal},
};
// 必须有的
int register_android_server_MyCustomService(JNIEnv *env) {
int res = jniRegisterNativeMethods(env, "com/android/server/MyCustomService", sMethods,
NELEM(sMethods));
if (res != 0) {
return -1;
}
return 0;
}
}
2. 在Android.bp文件中添加上面编写的JNI代码
在frameworks/base/services/core/jni/Android.bp中添加上面新增上面编写的jni代码文件,照葫芦画瓢即可。
cc_library_static {
name: "libservices.core",
defaults: ["libservices.core-libs"],
cflags: [
"-Wall",
"-Werror",
"-Wno-unused-parameter",
"-Wthread-safety",
"-DEGL_EGLEXT_PROTOTYPES",
"-DGL_GLEXT_PROTOTYPES",
],
srcs: [
"BroadcastRadio/JavaRef.cpp",
"BroadcastRadio/NativeCallbackThread.cpp",
"BroadcastRadio/BroadcastRadioService.cpp",
"BroadcastRadio/Tuner.cpp",
"BroadcastRadio/TunerCallback.cpp",
"BroadcastRadio/convert.cpp",
"BroadcastRadio/regions.cpp",
"com_android_server_AlarmManagerService.cpp",
"com_android_server_am_BatteryStatsService.cpp",
"com_android_server_connectivity_Vpn.cpp",
"com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp",
"com_android_server_ConsumerIrService.cpp",
"com_android_server_devicepolicy_CryptoTestHelper.cpp",
"com_android_server_HardwarePropertiesManagerService.cpp",
"com_android_server_hdmi_HdmiCecController.cpp",
"com_android_server_input_InputManagerService.cpp",
"com_android_server_lights_LightsService.cpp",
"com_android_server_location_GnssLocationProvider.cpp",
"com_android_server_locksettings_SyntheticPasswordManager.cpp",
"com_android_server_net_NetworkStatsService.cpp",
"com_android_server_power_PowerManagerService.cpp",
"com_android_server_security_VerityUtils.cpp",
"com_android_server_SerialService.cpp",
"com_android_server_storage_AppFuseBridge.cpp",
"com_android_server_SystemServer.cpp",
"com_android_server_TestNetworkService.cpp",
"com_android_server_tv_TvUinputBridge.cpp",
"com_android_server_tv_TvInputHal.cpp",
"com_android_server_vr_VrManagerService.cpp",
"com_android_server_UsbAlsaJackDetector.cpp",
"com_android_server_UsbDeviceManager.cpp",
"com_android_server_UsbDescriptorParser.cpp",
"com_android_server_UsbMidiDevice.cpp",
"com_android_server_UsbHostManager.cpp",
"com_android_server_VibratorService.cpp",
"com_android_server_PersistentDataBlockService.cpp",
"com_android_server_GraphicsStatsService.cpp",
"com_android_server_am_AppCompactor.cpp",
"com_android_server_am_LowMemDetector.cpp",
"com_android_server_MyCustomService.cpp", // 添加我们编写的JNI代码文件
"onload.cpp",
":lib_networkStatsFactory_native",
],
......
3. 注册jni
在frameworks/base/services/core/jni/onload.cpp中注册jni,比葫芦画瓢,随便找个JNI代码实现参照着写即可。
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <nativehelper/JNIHelp.h>
#include "jni.h"
#include "utils/Log.h"
#include "utils/misc.h"
#include "BroadcastRadio/BroadcastRadioService.h"
#include "BroadcastRadio/Tuner.h"
namespace android {
int register_android_server_AlarmManagerService(JNIEnv* env);
int register_android_server_BatteryStatsService(JNIEnv* env);
int register_android_server_ConsumerIrService(JNIEnv *env);
int register_android_server_InputManager(JNIEnv* env);
int register_android_server_LightsService(JNIEnv* env);
int register_android_server_PowerManagerService(JNIEnv* env);
int register_android_server_storage_AppFuse(JNIEnv* env);
int register_android_server_SerialService(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
int register_android_server_UsbAlsaJackDetector(JNIEnv* env);
int register_android_server_UsbDeviceManager(JNIEnv* env);
int register_android_server_UsbMidiDevice(JNIEnv* env);
int register_android_server_UsbHostManager(JNIEnv* env);
int register_android_server_vr_VrManagerService(JNIEnv* env);
int register_android_server_VibratorService(JNIEnv* env);
int register_android_server_location_GnssLocationProvider(JNIEnv* env);
int register_android_server_connectivity_Vpn(JNIEnv* env);
int register_android_server_connectivity_tethering_OffloadHardwareInterface(JNIEnv*);
int register_android_server_TestNetworkService(JNIEnv* env);
int register_android_server_devicepolicy_CryptoTestHelper(JNIEnv*);
int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
int register_android_server_tv_TvUinputBridge(JNIEnv* env);
int register_android_server_tv_TvInputHal(JNIEnv* env);
int register_android_server_PersistentDataBlockService(JNIEnv* env);
int register_android_server_Watchdog(JNIEnv* env);
int register_android_server_HardwarePropertiesManagerService(JNIEnv* env);
int register_android_server_SyntheticPasswordManager(JNIEnv* env);
int register_android_server_GraphicsStatsService(JNIEnv* env);
int register_android_hardware_display_DisplayViewport(JNIEnv* env);
int register_android_server_net_NetworkStatsFactory(JNIEnv* env);
int register_android_server_net_NetworkStatsService(JNIEnv* env);
int register_android_server_security_VerityUtils(JNIEnv* env);
int register_android_server_am_AppCompactor(JNIEnv* env);
int register_android_server_am_LowMemDetector(JNIEnv* env);
// 定义我们的注册函数,重点在这儿,重点在这儿,重点在这儿,重点在这儿
int register_android_server_MyCustomService(JNIEnv* env);
};
using namespace android;
extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
JNIEnv* env = NULL;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
ALOGE("GetEnv failed!");
return result;
}
ALOG_ASSERT(env, "Could not retrieve the env!");
register_android_server_broadcastradio_BroadcastRadioService(env);
register_android_server_broadcastradio_Tuner(vm, env);
register_android_server_PowerManagerService(env);
register_android_server_SerialService(env);
register_android_server_InputManager(env);
register_android_server_LightsService(env);
register_android_server_AlarmManagerService(env);
register_android_server_UsbDeviceManager(env);
register_android_server_UsbMidiDevice(env);
register_android_server_UsbAlsaJackDetector(env);
register_android_server_UsbHostManager(env);
register_android_server_vr_VrManagerService(env);
register_android_server_VibratorService(env);
register_android_server_SystemServer(env);
register_android_server_location_GnssLocationProvider(env);
register_android_server_connectivity_Vpn(env);
register_android_server_connectivity_tethering_OffloadHardwareInterface(env);
register_android_server_TestNetworkService(env);
register_android_server_devicepolicy_CryptoTestHelper(env);
register_android_server_ConsumerIrService(env);
register_android_server_BatteryStatsService(env);
register_android_server_hdmi_HdmiCecController(env);
register_android_server_tv_TvUinputBridge(env);
register_android_server_tv_TvInputHal(env);
register_android_server_PersistentDataBlockService(env);
register_android_server_HardwarePropertiesManagerService(env);
register_android_server_storage_AppFuse(env);
register_android_server_SyntheticPasswordManager(env);
register_android_server_GraphicsStatsService(env);
register_android_hardware_display_DisplayViewport(env);
register_android_server_net_NetworkStatsFactory(env);
register_android_server_net_NetworkStatsService(env);
register_android_server_security_VerityUtils(env);
register_android_server_am_AppCompactor(env);
register_android_server_am_LowMemDetector(env);
// 调用我们的注册函数,重点在这儿,重点在这儿,重点在这儿,重点在这儿
register_android_server_MyCustomService(env);
return JNI_VERSION_1_4;
}
4. 编译JNI
mmm -j20 frameworks/base/services/core/jni/

二、在服务中调用jni
在上一篇博客Android源码中添加AIDL服务实战,添加的自定义服务的基础上,进行修改。
1. 添加服务函数
修改/frameworks/base/core/java/android/os/IMyCustomService.aidl,添加myAdd服务函数。
package android.os;
/** @hide */
interface IMyCustomService{
// 带参数的示例
String processData(String input);
int myAdd(int a,int b);
}
2. 服务函数调用jni
修改frameworks/base/services/core/java/com/android/server/MyCustomService.java,实现myAdd服务函数。
package com.android.server;
import android.os.IMyCustomService;
import android.os.RemoteException;
import android.util.Slog;
import java.lang.Override;
import java.lang.String;
public class MyCustomService extends IMyCustomService.Stub {
private static final String TAG = "MyCustomService";
public MyCustomService() {
Slog.d(TAG, "Initialized");
}
@Override
public String processData(String input) throws RemoteException {
Slog.d(TAG, "Processing data: " + input);
return "Processed: " + input;
}
@Override
public int myAdd(int a,int b){
// 调用我们上面用C++编写的JNI函数
int ans = addValue(a, b);
Slog.d(TAG, "myAdd a + b = " + a + " + " + b + " = " + ans);
return ans;
}
// 添加native函数,具体实现就是我们上面JNI的实现
private static native int addValue(int a, int b);
}
3. 编译服务
mmm frameworks/base/ -j8
三、在相机代码中使用服务
1. 修改相机代码
修改packages/apps/Camera2/src/com/android/camera/CameraActivity.java,在mSessionListener的回调函数onSessionQueued中调用自定义服务my_custom_service中的myAdd函数。

try {
// IBinder binder = ServiceManager.getService("my_custom_service");
// IMyCustomService service = IMyCustomService.Stub.asInterface(binder);
Class<?> smClass = Class.forName("android.os.ServiceManager");
Method getService = smClass.getMethod("getService", String.class);
IBinder binder = (IBinder) getService.invoke(null, "my_custom_service");
IMyCustomService service = IMyCustomService.Stub.asInterface(binder);
String ans = service.processData("mekeater");
Log.v(TAG, "IMyCustomService processData: " + ans);
// 调用服务中的myAdd函数,而该函数具体实现是调用JNI函数
int add = service.myAdd(6,6);
Log.v(TAG, "IMyCustomService myAdd: " + add);
} catch (Exception e) {
Log.e(TAG, "call my_custom_service fail: ", e);
}
2. 编译相机
mmm packages/apps/Camera2/ -j8
四、打开虚拟机验证功能
emulator -writable-system
1. 桌面启动不了问题解决
- 相机权限缺失问题
因为相机缺少android.permission.BIND_WALLPAPER权限,导致桌面起不来
07-03 10:08:03.854 2044 2044 E AndroidRuntime: java.lang.IllegalStateException: Signature|privileged permissions not in privapp-permissions whitelist: {com.android.camera2: android.permission.BIND_WALLPAPER}
07-03 10:08:03.854 2044 2044 E AndroidRuntime: at com.android.server.pm.permission.PermissionManagerService.systemReady(PermissionManagerService.java:2970)
07-03 10:08:03.854 2044 2044 E AndroidRuntime: at com.android.server.pm.permission.PermissionManagerService.access$100(PermissionManagerService.java:122)
07-03 10:08:03.854 2044 2044 E AndroidRuntime: at com.android.server.pm.permission.PermissionManagerService$PermissionManagerServiceInternalImpl.systemReady(PermissionManagerService.java:3031)
07-03 10:08:03.854 2044 2044 E AndroidRuntime: at com.android.server.pm.PackageManagerService.systemReady(PackageManagerService.java:21785)
07-03 10:08:03.854 2044 2044 E AndroidRuntime: at com.android.server.SystemServer.startOtherServices(SystemServer.java:2001)
07-03 10:08:03.854 2044 2044 E AndroidRuntime: at com.android.server.SystemServer.run(SystemServer.java:514)
07-03 10:08:03.854 2044 2044 E AndroidRuntime: at com.android.server.SystemServer.main(SystemServer.java:351)
07-03 10:08:03.854 2044 2044 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
07-03 10:08:03.854 2044 2044 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
07-03 10:08:03.854 2044 2044 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:908)
在/frameworks/base/data/etc/privapp-permissions-platform.xml中添加该权限,重新编译framework/base

<permissions>
<privapp-permissions package="com.android.camera2">
<permission name="android.permission.BIND_WALLPAPER"/>
</privapp-permissions>
</permissions>
- 解决完上面的问题后,你会发现systemui又开始缺各种权限了,我懒得修改了,反正我们是验证,直接把抛异常的代码给干掉,让桌面跑起来,(但桌面可能有点异常,有黑屏卡顿现象,迁就着能用)
修改
frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java,把systemReady函数中权限检查的异常给注释掉,重新编译framework/base

3. 再启动虚拟机,执行以下命令
adb root
adb remount
adb sync
adb reboot
2. 将上面新编译的camera2.apk push到系统目录
adb root
adb remout
adb push out/target/product/generic_x86_64/system/product/priv-app/Camera2/Camera2.apk /system/product/app/Camera2/Camera2.apk
adb reboot
3. 关闭SELinux权限
adb root
adb remount
adb shell setenforce 0
4. 相机打不开问题解决
打开相机,这时候会报权限问题,相机打不开,从打开setting中打开相机,将相机位置权限打开,就可以正常打开相机了

5. 点击拍照,查看log,确认功能是否正常

可以看到myAdd函数功能正常,说明我们添加的JNI函数正常生效了。
后记
如何添加JNI,其实只有本博文中第一章的三个步骤,还是比较简单,比葫芦画瓢即可。但是在验证的过程中,会遇到各种问题,我们要学会解决修改android源码后,遇到的各种问题,可以通过查看log,找到问题原因,然后去问AI(如DeepSeek),相信在解决问题的过程中,就有自己越来越灵活的解决思路了。学习android源码的路上,我们一起加油。


1301

被折叠的 条评论
为什么被折叠?



