提供 NvramService 给 AS 直接调用(基于android10)

提供 NvramService 给 AS 直接调用(基于android10),第1张

概述最近对Nvram研究上瘾了,要读写nvram需要在安卓源码中编译才能调用相关API,这样局限性太大。本文的目的就是给系统增加一个NvramService让普通APP可直接读写nvram,类似这样的调用。WindowManagerwindowManager=(WindowManager)getSystemService(Context.WINDOW_S

最近对 Nvram 研究上瘾了,要读写 nvram 需要在安卓源码中编译才能调用相关 API,这样局限性太大。

本文的目的就是给系统增加一个 NvramService 让普通 APP 可直接读写 nvram,类似这样的调用。

WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);

display defaultdisplay = windowManager.getDefaultdisplay();

以下是本文最终实现的 API

NvramManager mNvramManager = (NvramManager)getSystemService(“NvramService”);

String buff2 = mNvramManager.readfileByname(PRODUCT_INFO_filename, 10);

源码最终编译成功后,需要将 out/target/common/obj/JAVA_liBRARIES/framework_intermediates/classes.jar@H_301_20@ 拷贝

到 AS 中,这样 apk 运行时就可调用 NvramManager

好了,不说废话了,来看如何实现吧!

1、新增com_androID_server_nvram_NvramService.cpp@H_301_20@

frameworks\base\services\core\jni\com_androID_server_nvram_NvramService.cpp

参考系统原有的 lightsService 服务,找到 frameworks\base\services\core\jni\ 路径,新增 com_androID_server_nvram_NvramService.cpp

/* * 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. com_androID_server_nvram_NvramService.cpp */#define LOG_TAG "NvramService"#include "jni.h"#include <nativehelper/JNIHelp.h>#include "androID_runtime/AndroIDRuntime.h"#include <vendor/mediatek/harDWare/nvram/1.0/INvram.h>#include <androID-base/chrono_utils.h>#include <utils/misc.h>#include <utils/Log.h>#include <map>#include <stdio.h>// #include <vector>using androID::sp;using androID::harDWare::hIDl_string;using vendor::mediatek::harDWare::nvram::V1_0::INvram;// using readfileByname_cb = std::function<voID(const ::androID::harDWare::hIDl_string& data)>;namespace androID {sp<INvram> hw_device;// hIDl_string result;Jstring charToJstring(jnienv* env, const char* pat){ jclass strClass = (env)->FindClass("java/lang/String"); jmethodID ctorID = (env)->getmethodID(strClass, "<init>", "([BLjava/lang/String;)V"); jbyteArray bytes = (env)->NewByteArray((Jsize)strlen(pat)); (env)->SetByteArrayRegion(bytes, 0, (Jsize)strlen(pat), (jbyte*)pat); Jstring enCoding = (env)->NewStringUTF("GB2312");  return (Jstring)(env)->NewObject(strClass, ctorID, bytes, enCoding);}char* Jstringtochar(jnienv* env, Jstring Jstr){    char* rtn = NulL;    jclass clsstring = env->FindClass("java/lang/String");    Jstring strencode = env->NewStringUTF("GB2312");    jmethodID mID = env->getmethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");    jbyteArray barr = (jbyteArray) env->CallObjectMethod(Jstr, mID, strencode);    Jsize alen = env->GetArrayLength(barr);    jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);    if (alen > 0) {        rtn = (char*) malloc(alen + 1);        memcpy(rtn, ba, alen);        rtn[alen] = 0;    }    env->ReleaseByteArrayElements(barr, ba, 0);    return rtn;}static Jstring nativeReadfileByname(jnienv* env, jobject /* clazz */,Jstring filename, jint size) {      ALOGE("androID_server_app_NvramService_nativeReadfileByname.....");      hw_device = INvram::getService();      if (hw_device == nullptr) {              ALOGW("Failed to get INvram service");              return filename;     }     ALOGE("success to get INvram service");      //std::string str = "abc";      //char* chardata = "abc".c_str();      //Jstring Jstr = charToJstring(env, chardata);      Jstring Jstr = env->NewStringUTF("abc");      char* chardata = Jstringtochar(env, filename);      ALOGE("Jstr=%s,name=%s\n", Jstringtochar(env, Jstr), chardata);      //hIDl_string &operator=(const filename);      //hw_device->readfileByname("/vendor/nvdata/APCFG/APRDEB/PRODUCT_INFO", size, result);      hw_device->readfileByname(chardata, size, [&](hIDl_string result) {                //printf("%s\n", result.c_str());            ALOGE("INvram service hIDl_string==%s\n",result.c_str());            //Jstr = result.c_str();            //Jstr = charToJstring(env, result.c_str());            Jstr = env->NewStringUTF(result.c_str());        });      // return charToJstring(env, chardata);      return Jstr;}static jint nativeWritefileBynamevec(jnienv*  env, jobject /* clazz */,                Jstring filename, jint size, Jstring data) {      ALOGE("androID_server_app_NvramService_nativeWritefileBynamevec.....");      hw_device = INvram::getService();        if (hw_device == nullptr) {              ALOGW("Failed to get INvram service");              return -1;     }     ALOGE("success to get INvram service");     char* cfilename = Jstringtochar(env, filename);     char* chardata = Jstringtochar(env, data);     ALOGE("filename=%s,chardata=%s\n", cfilename, chardata);     std::string strData = chardata;     std::vector<uint8_t> vecdata;      vecdata.assign(strData.begin(), strData.end());     jint rt = hw_device->writefileBynamevec(cfilename, size, vecdata);     return rt;}static const JNINativeMethod method_table[] = {    { "nativeReadfileByname", "(Ljava/lang/String;I)Ljava/lang/String;", (voID*)nativeReadfileByname },    { "nativeWritefileBynamevec", "(Ljava/lang/String;ILjava/lang/String;)I", (voID*)nativeWritefileBynamevec },};int register_androID_server_NvramService(jnienv *env) {    return jniRegisterNativeMethods(env, "com/androID/server/nvram/NvramService",            method_table, NELEM(method_table));}};

为啥要叫 com_androID_server_nvram_NvramService.cpp 这么长的名字呢?和系统其它保持一致这样看起来比较易懂,这样 cpp 文件对应的

NvramService.java 文件所处路径就为 frameworks/base/services/core/java/com/androID/server/nvram/NvramService.java

char* 转化为 Jstring,固定写法 jni 中经常用到

Jstring charToJstring(jnienv* env, const char* pat)

Jstring 转化为 char* ,固定写法 jni 中经常用到

char* Jstringtochar(jnienv* env, Jstring Jstr)

提供给 NvramService 调用读取指定 nvram 底层实现

static Jstring nativeReadfileByname(jnienv* env, jobject /* clazz */,Jstring filename, jint size)

提供给 NvramService 调用写入指定 nvram 底层实现

static jint nativeWritefileBynamevec(jnienv* env, jobject /* clazz */,Jstring filename, jint size, Jstring data)

固定写法,提供要注册到 NvramService 中方法表

static const JNINativeMethod method_table[]

这里需要注意的是 “(Ljava/lang/String;ILjava/lang/String;)I” ,这个代表 nativeWritefileBynamevec 方法传递三个参数,返回 int

{ “nativeWritefileBynamevec”, “(Ljava/lang/String;ILjava/lang/String;)I”, (voID*)nativeWritefileBynamevec },

Ljava/lang/String; Jstring filename

I jint size

ILjava/lang/String; Jstring data

I jint nativeWritefileBynamevec

这块不太好理解,我在这里耗费了很多时间才搞明白,可以参考这篇 Android JNI 使用的数据结构JNINativeMethod详解

固定写法,将上面 method_table 中方法注册到 NvramService 中

int register_androID_server_NvramService(jnienv *env)

对应两个方法具体实现逻辑不难,其中数据类型转换需要注意 hIDl_string 转 Jstring

有关 hIDl_string 相关介绍可参考官方介绍 HIDL(C++)数据类型

2、开机注册 com_androID_server_nvram_NvramService.cpp@H_301_20@

frameworks/base/services/core/jnI/Onload.cpp

 int register_androID_server_inputManager(jnienv* env); int register_androID_server_lightsService(jnienv* env);+int register_androID_server_NvramService(jnienv* env); int register_androID_server_PowerManagerService(jnienv* env); int register_androID_server_storage_AppFuse(jnienv* env); int register_androID_server_SerialService(jnienv* env);@@ -78,6 +79,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, voID* /* reserved */)     register_androID_server_SerialService(env);     register_androID_server_inputManager(env);     register_androID_server_lightsService(env);+    register_androID_server_NvramService(env);     register_androID_server_AlarmManagerService(env);     register_androID_server_UsbDeviceManager(env);     register_androID_server_UsbMIDIDevice(env);

3、AndroID.bp 添加编译 com_androID_server_nvram_NvramService.cpp@H_301_20@

frameworks/base/services/core/jni/AndroID.bp

         "com_androID_server_hdmi_HdmiCecController.cpp",         "com_androID_server_input_inputManagerService.cpp",         "com_androID_server_lights_lightsService.cpp",+        "com_androID_server_nvram_NvramService.cpp",         "com_androID_server_location_GnssLocationProvIDer.cpp",         "com_androID_server_locksettings_SyntheticPasswordManager.cpp",         "com_androID_server_net_NetworkStatsService.cpp",@@ -118,6 +119,7 @@ cc_defaults {         "androID.harDWare.input.classifIEr@1.0",         "androID.harDWare.ir@1.0",         "androID.harDWare.light@2.0",+        "vendor.mediatek.harDWare.nvram@1.0",         "androID.harDWare.power@1.0",         "androID.harDWare.power@1.1",         "androID.harDWare.power.stats@1.0",

上面三步完成后,jni 部分就已搞定,接下来再增加 framework 中 NvramService

4、新增 INvramService.aIDl@H_301_20@

frameworks\base\core\java\androID\app\INvramService.aIDl

package androID.app;interface INvramService {    String readfileByname(in String filename, int size);    int writefileBynamevec(in String filename, int size, in String data);}

注意别加 @hIDe 注释,不然在 NvramManager 中传递时会报如下错误

alps/frameworks/base/core/java/androID/app/NvramManager.java:17: error: Class androID.os.INvramService is hIDden but was referenced (as parameter type) from public parameter service in androID.app.NvramManager(androID.content.Context ctx, androID.os.INvramService service) [ReferencesHIDden]
17:09:20 ninja Failed with: exit status 1

5、AndroID.bp 添加编译 INvramService.aIDl@H_301_20@

frameworks\base\AndroID.bp

         "core/java/androID/app/usage/ICacheQuotaService.aIDl",         "core/java/androID/app/usage/IStorageStatsManager.aIDl",         "core/java/androID/app/usage/IUsageStatsManager.aIDl",+        "core/java/androID/app/INvramService.aIDl",         ":libbluetooth-binder-aIDl",         "core/java/androID/content/IClipboard.aIDl",         "core/java/androID/content/IContentService.aIDl",

6、新增 NvramService.java@H_301_20@

frameworks\base\services\core\java\com\androID\server\nvram\NvramService.java

注意 native 方法名称要和 jni 中对应才能成功注册服务

/* * copyright (C) 2008 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. */package com.androID.server.nvram;import com.androID.server.SystemService;import androID.app.ActivityManager;import androID.app.INvramService;import androID.content.Context;import androID.os.Handler;import androID.os.Message;import androID.os.Trace;import androID.provIDer.Settings;import androID.util.Slog;public class NvramService extends INvramService.Stub {    static final String TAG = "NvramService";    static final boolean DEBUG = false;    public NvramService(){      androID.util.Log.d(TAG,"Start NvramService...");    }        @OverrIDe     public String readfileByname(String filename,int size){      androID.util.Log.d(TAG,"NvramService readfileByname()...filename="+ filename);      return nativeReadfileByname(filename, size);    }    @OverrIDe     public int writefileBynamevec(String filename,int size, String data){      androID.util.Log.d(TAG,"NvramService writefileBynamevec()...filename="+filename);      return nativeWritefileBynamevec(filename, size, data);    }    public static native String nativeReadfileByname(String filename,int size);    public static native int nativeWritefileBynamevec(String filename,int size, String data);   }

7、在 SystemServer 中注册 NvramService@H_301_20@

frameworks\base\services\java\com\androID\server\SystemServer.java

           traceBeginAndSlog("PinnerService");           mSystemServiceManager.startService(PinnerService.class);           traceEnd();           traceBeginAndSlog("SignedConfigService");           SignedConfigService.registerUpdateReceiver(mSystemContext);           traceEnd();+           +            ServiceManager.addService("NvramService", new com.androID.server.nvram.NvramService());+                 } catch (RuntimeException e) {             Slog.e("System", "******************************************");             Slog.e("System", "************ Failure starting core service", e);

8、提供 NvramManager 并代理 INvramService@H_301_20@

frameworks\base\core\java\androID\app\SystemServiceRegistry.java

代码中的"NvramService",标准写法在 Context 中新增常量,这里就不写了

                 return new AlarmManager(service, ctx);             }}); +        registerService("NvramService", NvramManager.class,+                new CachedServiceFetcher<NvramManager>() {+            @OverrIDe+            public NvramManager createService(ContextImpl ctx) {+                try{+                    IBinder b = ServiceManager.getServiceOrThrow("NvramService");+                    INvramService service = INvramService.Stub.asInterface(b);+                    return new NvramManager(ctx, service);+                }catch(ServiceNotFoundException e){+                    return new NvramManager(ctx, null);+                }+            }});+         registerService(Context.AUdio_SERVICE, AudioManager.class,                 new CachedServiceFetcher<AudioManager>() {

frameworks\base\core\java\androID\app\NvramManager.java

package androID.app;  import androID.annotation.SdkConstant;import androID.annotation.SystemAPI;import androID.content.Context;import androID.content.Intent;import androID.os.Build;import androID.os.Parcel;import androID.os.Parcelable;import androID.os.remoteexception;import androID.util.Log; public class NvramManager {    public String TAG = "NvramManager";     INvramService mService;    public NvramManager(Context ctx, INvramService service){        mService = service;    }        public String readfileByname(String filename, int size){		Log.d(TAG,"NvramManager readfileByname()...filename="+filename);        try{            return mService.readfileByname(filename, size);        }catch(Exception e){            Log.e(TAG,e.toString());            e.printstacktrace();        }        return "111";    }    public int writefileBynamevec(String filename, int size, String data){      Log.d(TAG,"NvramManager writefileBynamevec()...filename="+filename);      try{            return mService.writefileBynamevec(filename, size, data);      }catch(Exception e){          Log.e(TAG,e.toString());          e.printstacktrace();      }      return -1;    }}

到这里 NvramService 服务就成功注册了,先执行 make API-stubs-docs-update-current-API 命令更新系统 API

然后在重新 make 项目

9、一些坑集锦@H_301_20@

烧写开机后 NvramService 无法启动

2021-01-29 14:22:52.915 373-373/? E/SElinux: avc: denIEd { add } for service=NvramService pID=1080 uID=1000 scontext=u:r:system_server:s0 tcontext=u:object_r:default_androID_service:s0 tclass=service_manager permissive=0
2021-01-29 14:22:52.915 373-373/? E/ServiceManager: add_service(‘NvramService’,52) uID=1000 - PERMISSION DENIED

增加对应 selinux 权限

device\mediatek\sepolicy\basic\non_plat\system_server.te@H_301_20@

allow system_server default_androID_service:service_manager add;

再次重新 make,编译报错

libsepol.report_failure: neverallow on line 509 of system/sepolicy/public/domain.te (or line 11816 of policy.conf) violated by allow system_server default_androID_service:service_manager { add };
libsepol.check_assertions: 1 neverallow failures occurred
Error while expanding policy

根据提示去除509行相应权限检测

system\sepolicy\public\domain.te@H_301_20@
system\sepolicy\prebuilts\API\29.0\public\domain.te@H_301_20@

#neverallow * default_androID_service:service_manager add;neverallow * default_androID_vndservice:service_manager { add find };neverallow * default_androID_hwservice:hwservice_manager { add find };

服务成功启动,导入 classes.jar 成功,调用 readfileByname 或者 writefileBynamevec 时

又出现权限问题

SElinux: avc: denIEd { find } for interface=vendor.mediatek.harDWare.nvram::INvram sID=u:r:system_server:s0 pID=1075 scontext=u:r:system_server:s0 tcontext=u:object_r:nvram_agent_binder_hwservice:s0 tclass=hwservice_manager permissive=0

Binder:1060_8: type=1400 audit(0.0:2715): avc: denIEd { call } for scontext=u:r:system_server:s0 tcontext=u:r:nvram_agent_binder:s0 tclass=binder permissive=0

最终 system_server.te 修改如下

device\mediatek\sepolicy\basic\non_plat\system_server.te@H_301_20@

allow system_server default_androID_service:service_manager add;allow system_server nvram_agent_binder_hwservice:hwservice_manager find;allow system_server nvram_agent_binder:binder call;

如果无法成功写入数据能正常读取数据,还需要关闭写保护,注释 set_write_protect()

vendor\mediatek\proprIEtary\bootable\bootloader\lk\platform\mt6765\write_protect.c@H_301_20@

if (!bypass_wp) {
// set_write_protect();
pal_log_err(“write protect Done! \n”);
} else
pal_log_err(“Bypass write protect! \n”);

AS 中两种调用 NvramService 方式

 		NvramManager mNvramManager = (NvramManager)getSystemService("NvramService");        String buff2 = mNvramManager.readfileByname(PRODUCT_INFO_filename, 10);        Log.e(TAG, " buff2="+buff2);                INvramService nvramService = INvramService.Stub.asInterface(getService("NvramService"));        String buff = "1";        try {            buff = nvramService.readfileByname(PRODUCT_INFO_filename, 10);        } catch (remoteexception e) {            e.printstacktrace();        }        Log.d(TAG, " buff="+buff);

Android驱动学习-app调用内核驱动过程(驱动框架回顾)

AndroidQ 打通应用层到HAL层—(JNI服务和AIDL服务实现)

总结

以上是内存溢出为你收集整理的提供 NvramService 给 AS 直接调用(基于android10)全部内容,希望文章能够帮你解决提供 NvramService 给 AS 直接调用(基于android10)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1044694.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-24
下一篇 2022-05-24

发表评论

登录后才能评论

评论列表(0条)

保存