Android13源码添加系统服务

news2024/9/23 23:25:53

本文基于Android 13的framework层添加系统接口,为应用层提供读写函数、以及执行命令!

添加接口

frameworks/base/core/java/android/app/IDevices.aidl

package android.app;
interface IDevices
{
    //读取文件
    String readFile(String path);
    //写入文件
    void writeFile(String path,String data);
    //执行shell命令
    String shellExec(String cmd);
}

添加系统服务的Manager

frameworks/base/core/java/android/app/DevicesManager.java

package android.app;

import android.annotation.SystemService;
import android.content.Context;
import android.os.RemoteException;
import android.util.Slog;

@SystemService(Context.DEVICES_SERVICE)
public class DevicesManager {
    Context mContext;
    IDevices mService;

    public DevicesManager(Context context,IDevices service){
        if(service==null){
            Slog.e("DevicesManager","Construct service is null");
        }
        mContext = context;
        mService = service;
    }

    public String shellExec(String cmd){
        if(mService != null){
            try{
                Slog.e("DevicesManager","shellExec");
                return mService.shellExec(cmd);
            }catch(RemoteException e){
                Slog.e("DevicesManager","RemoteException "+e);
            }
        }else{
            Slog.e("DevicesManager","mService is null");
        }
        return "";
    }

    public String readFile(String path){
        if(mService != null){
            try{
                Slog.e("DevicesManager","readFile");
                return mService.readFile(path);
            }catch(RemoteException e){
                Slog.e("DevicesManager","RemoteException "+e);
            }
        }else{
            Slog.e("DevicesManager","mService is null");
        }
        return "";
    }

    public void writeFile(String path,String data){
        if(mService != null){
            try{
                Slog.e("DevicesManager","writeFile");
                mService.writeFile(path,data);
            }catch(RemoteException e){
                Slog.e("DevicesManager","RemoteException "+e);
            }
        }else{
            Slog.e("DevicesManager","mService is null");
        }
    }

}

添加系统服务,实现aidl文件的接口

frameworks/base/services/core/java/com/android/server/DevicesService.java

package com.android.server; 

import android.app.IDevices;
import android.content.Context;
import android.os.Build;
import android.util.Log;
import android.util.Slog;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
 
import libcore.io.IoUtils;
 
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.RandomAccessFile;
 
import android.util.Base64;
 
 
public class DevicesService extends IDevices.Stub {
    private Context mContext;
    private String TAG="DevicesService";
    public DevicesService(Context context){
        super();
        mContext = context;
        Slog.d(TAG,"Construct");
    }
 
    @Override
    public String shellExec(String cmd){
        Runtime mRuntime = Runtime.getRuntime();
        try {
            //Process中封装了返回的结果和执行错误的结果
            Slog.d(TAG,"shellExec data:"+cmd);
            Process mProcess = mRuntime.exec(cmd);
            BufferedReader mReader = new BufferedReader(new InputStreamReader(mProcess.getInputStream()));
            StringBuffer mRespBuff = new StringBuffer();
            char[] buff = new char[1024];
            int ch = 0;
            while ((ch = mReader.read(buff)) != -1) {
                mRespBuff.append(buff, 0, ch);
            }
            mReader.close();
            return mRespBuff.toString();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            Slog.d(TAG,"shellExec err:"+e.getMessage());
        }
        return "";
    }
 
 
    public static void writeTxtToFile(String strcontent, String filePath) {
        String strFilePath = filePath;
        String strContent = strcontent + "\n";  // \r\n 结尾会变成 ^M
        try {
            File file = new File(strFilePath);
            makeFilePath(file.getParent(),file.getName());
            if (!file.exists()) {
                file.getParentFile().mkdirs();
                file.createNewFile();
            }
            RandomAccessFile raf = new RandomAccessFile(file, "rwd");
            raf.setLength(0);
 
            // 写文件的位置标记,从文件开头开始,后续读取文件内容从该标记开始
            long writePosition = raf.getFilePointer();
            raf.seek(writePosition);
            raf.write(strContent.getBytes());
            raf.close();
            //
        } catch (Exception e) {
            Log.d("DevicesService","Error on write File:" + e);
        }
    }
 
    // 生成文件
    public static File makeFilePath(String filePath, String fileName) {
        File file = null;
        makeRootDirectory(filePath);
        try {
            file = new File(filePath +"/"+ fileName);
            if (!file.exists()) {
                file.createNewFile();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return file;
    }
 
    // 生成文件夹
    public static void makeRootDirectory(String filePath) {
        File file = null;
        try {
            Log.d("FileHelper", "makeRootDirectory "+filePath);
            file = new File(filePath);
            if (!file.exists()) {
                boolean isok= file.mkdir();
                Log.d("FileHelper", "makeRootDirectory "+filePath+" "+isok);
            }
        } catch (Exception e) {
            Log.d("DevicesService", e+"");
        }
    }
 
    public static String readFileAll(String path) {
        File file = new File(path);
        StringBuilder sb=new StringBuilder();
        if (file != null && file.exists()) {
            InputStream inputStream = null;
            BufferedReader bufferedReader = null;
            try {
                inputStream = new FileInputStream(file);
                bufferedReader = new BufferedReader(new InputStreamReader(
                        inputStream));
                String outData;
                while((outData=bufferedReader.readLine())!=null){
                    sb.append(outData+"\n");
                }
            } catch (Throwable t) {
            } finally {
                try {
                    if (bufferedReader != null) {
                        bufferedReader.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                try {
                    if (inputStream != null) {
                        inputStream.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }
 
 
    @Override
    public String readFile(String path){
        return readFileAll(path);
    }
    @Override
    public void writeFile(String path,String data){
        writeTxtToFile(data,path);
    }
 
}

添加服务名称

frameworks/base/core/java/android/content/Context.java

        @StringDef(suffix = { "_SERVICE" }, value = {
                POWER_SERVICE,
/*add_longzhiye*/++    DEVICES_SERVICE,
                //@hide: POWER_STATS_SERVICE,
                WINDOW_SERVICE,
                LAYOUT_INFLATER_SERVICE,
                ACCOUNT_SERVICE,
                ACTIVITY_SERVICE,
                ALARM_SERVICE,
 
 
 
  public static final String POWER_SERVICE = "power";
++public static final String DEVICES_SERVICE = "devices";

将实现的服务注册到系统中去

frameworks/base/core/java/android/app/SystemServiceRegistry.java

registerService(Context.SEARCH_SERVICE, SearchManager.class,
        new CachedServiceFetcher<SearchManager>() {
    @Override
    public SearchManager createService(ContextImpl ctx) throws ServiceNotFoundException {
        return new SearchManager(ctx.getOuterContext(),
                ctx.mMainThread.getHandler());
    }});
//add longzhiye
registerService(Context.DEVICES_SERVICE,DevicesManager.class,
        new CachedServiceFetcher<DevicesManager>(){
    @Override
    public DevicesManager createService(ContextImpl ctx){
        IBinder b = ServiceManager.getService(Context.DEVICES_SERVICE);
        return new DevicesManager(ctx,IDevices.Stub.asInterface(b));
                } });   
//add end       
registerService(Context.SENSOR_SERVICE, SensorManager.class,
        new CachedServiceFetcher<SensorManager>() {
    @Override
    public SensorManager createService(ContextImpl ctx) {
        return new SystemSensorManager(ctx.getOuterContext(),
          ctx.mMainThread.getHandler().getLooper());
    }});

将注册的服务设置成开机启动服务

frameworks/base/services/java/com/android/server/SystemServer.java

t.traceBegin("StartTelephonyRegistry");
telephonyRegistry = new TelephonyRegistry(
        context, new TelephonyRegistry.ConfigurationProvider());
ServiceManager.addService("telephony.registry", telephonyRegistry);
t.traceEnd();
//add longzhiye
t.traceBegin("StartDevicesService");
try{
    ServiceManager.addService(Context.DEVICES_SERVICE,new DevicesService(context));
} catch(Throwable e){
    Slog.e("DevicesService","Failed to start DevicesService Service "+e);
}
t.traceEnd();
//add end

让lint检查忽略掉自己的模块

注(Android 11 以后谷歌强制开启lint检查,lint检查不过编译会报错)

frameworks/base/Android.bp

// TODO(b/145644363): move this to under StubLibraries.bp or ApiDocs.bp
metalava_framework_docs_args = "" +
    "--api-lint-ignore-prefix android.app. " +     //add_longzhiye
    "--api-lint-ignore-prefix android.icu. " +
    "--api-lint-ignore-prefix java. " +
    "--api-lint-ignore-prefix junit. " +
    "--api-lint-ignore-prefix org. " +
    "--error NoSettingsProvider " +
    "--error UnhiddenSystemApi " +
    "--force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.* " +
    "--hide BroadcastBehavior " +
    "--hide CallbackInterface " +
    "--hide DeprecationMismatch " +
    "--hide HiddenSuperclass " +
    "--hide HiddenTypeParameter " +
    "--hide MissingPermission " +
    "--hide-package android.audio.policy.configuration.V7_0 " +
    "--hide-package com.android.server " +
    "--hide RequiresPermission " +
    "--hide SdkConstant " +
    "--hide Todo " +
    "--hide Typo " +
    "--hide UnavailableSymbol " +
    "--manifest $(location core/res/AndroidManifest.xml) "

编译源码 更新api接口

make update-api

检查服务是否开启

将编译好的rom 刷入手机,查看sevice list
这里可以看到我们的服务 已经启动了:
服务名称:79 devices: [android.app.IDevices]

longzhiye@longzhiye-laptop:~$ adb shell
coral:/ # service list |grep Device
60    companiondevice: [android.companion.ICompanionDeviceManager]
75    device_identifiers: [android.os.IDeviceIdentifiersPolicyService]
76    device_policy: [android.app.admin.IDevicePolicyManager]
77    device_state: [android.hardware.devicestate.IDeviceStateManager]
78    deviceidle: [android.os.IDeviceIdleController]
79    devices: [android.app.IDevices]
251    virtualdevice: [android.companion.virtual.IVirtualDeviceManager]
coral:/ #

调用测试

应用层项目中引入aidl

// IDevices.aidl
package android.app;
 
// Declare any non-default types here with import statements
 
interface IDevices {
        String shellExec(String cmd);
        String readFile(String path);
        void writeFile(String path,String data);
}


调用测试:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1141204.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

hdlbits系列verilog解答(模块按位置)-21

文章目录 一、问题描述二、verilog源码三、仿真结果 一、问题描述 此问题类似于上一个&#xff08;模块&#xff09;。您将获得一个名为的 mod_a 模块&#xff0c;该模块按此顺序具有 2 个输出和 4 个输入。您必须按位置将 6 个端口按该顺序连接到顶级模块的端口 out1 、 out2…

Mac-postman存储文件目录

今天postman弹窗要求登录账号才可访问之前的API文档数据。 但是这postman的账号又是前同事的账号&#xff0c;我没有他的账号和密码啊。 登录了我自己的postman账号后&#xff0c;所有的api文档都不见了....我服了。 首先去屏幕左上角---> 前往 --->个人 然后键盘按显…

【算法练习Day30】无重叠区间 划分字母区间合并区间

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 无重叠区间划分字母区间合并…

力扣在线OJ——栈和队列

目录 &#x1f341;一、用两个队列实现栈 &#x1f315;&#xff08;一&#xff09;、题目&#xff08;力扣链接&#xff1a;用队列实现栈 &#xff09; &#x1f315;&#xff08;二&#xff09;、注意 &#x1f315;&#xff08;三&#xff09;、解答 ⭐️1.注意事项 ⭐…

Java练习题2021-2

"某地大数据防疫平台记录了往来的所有防疫相关信息&#xff0c;包括 本地或外地人员、健康码颜色、接种疫苗情况、最近一次核酸结果、最近一次核酸检测时间等。 该地某区域对于进入人员的要求为&#xff1a; 如果是本地人员&#xff0c;需要绿码和疫苗完全接种方可进入&am…

单位建数字档案室的意义和作用

单位建立数字档案室的意义和作用包括&#xff1a; 1.提高档案管理效率。数字档案室可以高效地收集、整理和存储电子文档&#xff0c;通过数字化处理&#xff0c;文档的查找和检索速度大幅提升。 2.降低管理成本。数字档案室可以通过节约空间和人力成本&#xff0c;降低管理成本…

ubuntu扩大运行内存, 防止编译卡死

首先查看交换分区大小 grep SwapTotal /proc/meminfo 1、关闭交换空间 sudo swapoff -a 2、扩充交换空间大小&#xff0c;count64就是64G 1G x 64 sudo dd if/dev/zero of/swapfile bs1G count64 3、设置权限 sudo chmod 600 /swapfile 4、指定交换空间对应的设备文件 …

系列十四、Spring如何处理线程安全问题

一、线程安全问题出现的原因 Spring中出现线程安全的原因是&#xff0c;单实例bean中存在成员变量&#xff0c;并且有对这个bean进行读写的操作&#xff0c;因此出现了线程安全的问题。 二、案例代码 2.1、MySpringConfig /*** Author : 一叶浮萍归大海* Date: 2023/10/24 1…

假脱机技术(SPOOLing技术)

文章目录 1.什么是脱机技术1.脱机技术解决的问题 2.假脱机技术的实现原理1.输入井和输出井2.输入进程和输出进程3,输入缓冲区和输出缓冲区 3.共享打印机的原理分析1.把独占式的打印机改造成共享设备 1.什么是脱机技术 脱机&#xff1a;脱离主机的控制进行的输入输出操作。 批处…

【1++的Linux】之进程间通信(共享内存)

&#x1f44d;作者主页&#xff1a;进击的1 &#x1f929; 专栏链接&#xff1a;【1的Linux】 我们在前面的文章中提到过&#xff0c;进程间的通信本质都是先看到同一块资源&#xff0c;然后通过这同一块资源进行通信&#xff0c;并且是单向的通信&#xff0c;只能一端发&#…

可视化 | (四)可视化降维

文章目录 &#x1f4da;降维的重要性&#x1f4da;MDS、PCA&#x1f407;MDS&#x1f407;PCA &#x1f4da;SNE&#x1f407;总述&#x1f407;SNE&#x1f407;Symmetric-SNE&#x1f407;T-SNE &#x1f4da;降维的重要性 降维在数据分析和可视化领域中扮演着重要的角色。当…

19、Python -- 关键字参数 与 参数默认值,参数收集 与 逆向参数收集

目录 关键字参数位置参数&#xff1a;关键字参数位置参数和关键字参数的混合使用关键字参数注意点 参数默认值使用参数默认值 普通参数收集&#xff08;*xxx&#xff09;注意点 关键字参数收集(**xxx)逆向参数收集注意点&#xff1a; dict&#xff08;字典&#xff09;的逆向参…

J2EE项目部署与发布(Windows版本)

目录 一.会议OA单体项目Windows部署 1.实操 二.spa前后端分离项目Windows部署 1.部署后端 2.部署前端 配置node.js 3.从实施的角度 4.从开发的角度 ​编辑 一.会议OA单体项目Windows部署 我们从实施的角度来看&#xff0c;拿到项目之后一定要问开发人员提供数据库脚…

SpringCloud复习:(8)Zuul内置过滤器

过滤器的执行顺序&#xff1a;根据filterOrder方法的返回值&#xff0c;返回值&#xff08;包含负数&#xff09;越小&#xff0c;越早执行 。 FilterProcessor类中会调用filter的runFilter方法 ZuulFilter中的runFilter方法会调用run方法&#xff1a;

在ffmpeg中,网络视频流h264为什么默认的转为YUV而不是其他格式

在做网络视频的时候&#xff0c;有些视频的编程概念&#xff0c;早点知道&#xff0c;早点弄清楚会少走很多的弯路。对应视频的转码&#xff0c;传输&#xff0c;一开始如果直接跟着代码跑的话&#xff0c;很容易觉得自己都明白了&#xff0c;但是为什么这样做&#xff0c;好像…

使用WebStorm创建和配置TypeScript项目

创建 这里我用的是WebStorm 2019.2.2版本 首先&#xff0c;创建一个空项目 File -> New -> Project->Empty Project生成配置文件 自动配置&#xff1a; 打开终端输入tsc --init&#xff0c;即可自动生成tsconfig.json文件 手动配置&#xff1a; 在项目根目录下新建一…

第四章 文件管理 八、文件保护

目录 一、口令保护 1、定义&#xff1a; 2、优点&#xff1a; 3、缺点: 二、加密保护 1、定义&#xff1a; 2、例子&#xff1a; 2、优点&#xff1a; 3、缺点: 三、访问控制 1、定义&#xff1a; 2、精简的访问控制表&#xff1a; &#xff08;1&#xff09;定义&a…

海南海口大型钢结构件3D扫描全尺寸三维测量平面度平行度检测-CASAIM中科广电

高精度三维扫描技术已经在大型工件制造领域发挥着重要作用&#xff0c;特别是在质量检测环节&#xff0c;高效、高精度&#xff0c;可以轻松实现全尺寸三维测量。本期&#xff0c;CASAIM要分享的应用是在大型钢结构件的关键部位尺寸及形位公差检测。 钢结构件&#xff0c;是将…

38 深度学习(二):tensorflow基础介绍

文章目录 tensorflow基础介绍基础张量自定义损失函数自定义模型和激活函数图函数&#xff08;略&#xff09;自动求导机制自定义fit tensorflow基础介绍 基础张量 import tensorflow as tf import numpy as np import pandas as pd# constant是常量张量 不能进行再次assign改…

【ETL工具】Datax-ETL-SqlServerToHDFS

&#x1f984; 个人主页——&#x1f390;个人主页 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341; 感谢点赞和关注 &#xff0c;每天进步一点点&#xff01;加油&#xff01;&…