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

调用测试:

相关推荐
Live0000012 分钟前
在鸿蒙中使用 Repeat 渲染嵌套列表,修改内层列表的一个元素,页面不会更新
前端·javascript·react native
阿巴斯甜7 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker7 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95278 小时前
Andorid Google 登录接入文档
android
黄林晴10 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android