Android13源码添加系统服务

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

添加接口

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

java 复制代码
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

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

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

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

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

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

java 复制代码
// 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接口

bash 复制代码
make update-api

检查服务是否开启

将编译好的rom 刷入手机,查看sevice list

这里可以看到我们的服务 已经启动了:

服务名称:79 devices: [android.app.IDevices]

bash 复制代码
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

java 复制代码
// 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);
}

调用测试:

相关推荐
拭心2 小时前
Google 提供的 Android 端上大模型组件:MediaPipe LLM 介绍
android
带电的小王4 小时前
WhisperKit: Android 端测试 Whisper -- Android手机(Qualcomm GPU)部署音频大模型
android·智能手机·whisper·qualcomm
梦想平凡5 小时前
PHP 微信棋牌开发全解析:高级教程
android·数据库·oracle
元争栈道5 小时前
webview和H5来实现的android短视频(短剧)音视频播放依赖控件
android·音视频
阿甘知识库6 小时前
宝塔面板跨服务器数据同步教程:双机备份零停机
android·运维·服务器·备份·同步·宝塔面板·建站
元争栈道6 小时前
webview+H5来实现的android短视频(短剧)音视频播放依赖控件资源
android·音视频
MuYe6 小时前
Android Hook - 动态加载so库
android
居居飒7 小时前
Android学习(四)-Kotlin编程语言-for循环
android·学习·kotlin
Henry_He10 小时前
桌面列表小部件不能点击的问题分析
android
工程师老罗10 小时前
Android笔试面试题AI答之Android基础(1)
android