Android11 framework添加系统服务

在Android11中添加了很多新特性,编译脚本也进行了比较大的改动。例如如果一个系统方法添加了@hide即使使用反射也无法进行函数调用,另外对于public方法如果含有包装类型参数或者返回值时必须添加 @NonNull 不能为空 以及 @Nullable 可为空 进行注解否则会导致 make update-api 失败。另外相对Android7我们在core中添加AIDL后无需再编译脚本中进行添加,因为Android11使用了.java和.aidl进行通配。

新键AIDL文件
frameworks/core/java/android/app/IDevInfoManager.aidl

package android.app;

/**
*@hide
*/
interface IDevInfoManager{
   String getValue(String name);
   int update(String name,String value,int attribute);
}

添加Context常量
frameworks/core/java/android/content/Context.java b/core/java/android/content/Context.java

    /**
     * add sunniwell
     * 用于获取系统的一些数据接口服务
     * 
     */
    public static final String DATA_SERVICE = "data";

添加服务配置文件
frameworks/services/devinfo/Android.bp

filegroup {
    name: "services.devinfo-sources",
    srcs: ["java/**/*.java"],
    path: "java",
    visibility: ["//frameworks/base/services"],
}

java_library_static {
    name: "services.devinfo",
    defaults: ["services_defaults"],
    srcs: [":services.devinfo-sources"],
    libs: ["services.core"],
}

请留意services.devinfo-sourcesservices.devinfo两个参数。

Java服务实现
frameworks/services/devinfo/java/com/android/server/devinfo/DevInfoManagerService.java

package com.android.server.devinfo;

import android.app.DevInfoManager;
import android.app.IDevInfoManager;
import android.content.Context;

public class DevInfoManagerService extends IDevInfoManager.Stub {
   private mValue;
  public DevInfoManagerService(Context context) {
    this.mContext = context;
      loadDefaultDevinfo();
  }

  private void loadDefaultDevinfo() {
  mValue="hello"
  }

  @Override
  public String getValue(String name) throws RemoteException {
    return mValue;
  }

  @Override
  public int update(String name, String value, int attribute)
    throws RemoteException, SecurityException {
    int ret = 0;
    mValue = value;
    return ret;
  }

}

将服务添加至编译脚本
frameworks/services/Android.bp

filegroup {
    name: "services-all-sources",
    srcs: [
        .....
        ":services.devinfo-sources",
        ....
    ],
    visibility: ["//visibility:private"],
}

...
java_library {
    name: "services",
    installable: true,

    dex_preopt: {
        app_image: true,
        profile: "art-profile",
    },

    srcs: [":services-main-sources"],

    // The convention is to name each service module 'services.$(module_name)'
    static_libs: [
        ...
        "services.devinfo",
         ...
    ],

    libs: [
        "android.hidl.manager-V1.0-java",
        "framework-tethering.stubs.module_lib",
    ],

    // Uncomment to enable output of certain warnings (deprecated, unchecked)
    //javacflags: ["-Xlint"],
}

请留意:services.devinfo-sourcesservices.devinfo两个参数。

将服务添加至系统
frameworks/services/java/com/android/server/SystemServer.java

import com.android.server.devinfo.DevInfoManagerService;

....
        t.traceBegin("StartDevInfoManagerService");
        try {
         ServiceManager.addService(Context.DATA_SERVICE, new DevInfoManagerService(context));
        } catch (Throwable e) {
            Slog.e(TAG, "Failure starting System DevInfoManager Service ", e);
        }
        t.traceEnd();
...

注意由于该服务属于自定义请将其添加子otherSerice方法比较合理。

注册服务使得可以通过 DevInfoManager mDevInfoManager = (DevInfoManager) mContext.getSystemService(Context.DATA_SERVICE);获取到服务。
frameworks/core/java/android/app/SystemServiceRegistry.java

import android.app.DevInfoManager;
import android.app.IDevInfoManager;

....
    registerService(Context.DATA_SERVICE,DevInfoManager.class,
      new CachedServiceFetcher<DevInfoManager>() {
        @Override
        public DevInfoManager createService(ContextImpl ctx) throws ServiceNotFoundException{
          IBinder b = ServiceManager.getServiceOrThrow(Context.DATA_SERVICE);
          IDevInfoManager service = IDevInfoManager.Stub.asInterface(b);
          if (service == null) {
            return null;
          }
          return new DevInfoManager(ctx.getOuterContext(), service);
        }
      }
    );
...

添加DevInfoManager接口
frameworks/core/java/android/app/DevInfoManager.java

package android.app;

import android.app.IDevInfoManager;
import android.content.Context;
import android.os.RemoteException;
import android.util.Slog;
import android.annotation.NonNull;
import android.annotation.Nullable;

public class DevInfoManager {

  private Context mContext;
  private IDevInfoManager mService;

  /** @hide */
  public DevInfoManager(Context context, IDevInfoManager service) {
    mContext = context;
    mService = service;
  }

  /**
   * 获取参数
   * 
   */
  @Nullable
  public  String getValue(@NonNull String paramString) {
    String value = null;
    if (mService != null && paramString != null) {
      try {
        value = mService.getValue(paramString);
      } catch (RemoteException e) {
        Slog.e("SystemStatus", "RemoteException " + e);
      }
    }
    return value;
  }

  /**
   * update DevInfo
   *
   */
  public int update(@NonNull String paramString1,@NonNull String paramString2, int paramInt) {
    int ret = -1;
    if (mService != null&& paramString1 != null && paramString2 != null) {
      try {
        ret = mService.update(paramString1, paramString2, paramInt);
      } catch (RemoteException e) {
        Slog.e("SystemStatus", "RemoteException " + e);
      }
    }

    return ret;
  }
}

请留意文章开头提到的@NonNull 不能为空 以及 @Nullable 可为空否则make update-api会出现以下错误:

frameworks/base/core/java/android/app/DevInfoManager.java:xx: error: Missing nullability on method `getValue` return [MissingNullability]
frameworks/base/core/java/android/app/DevInfoManager.java:xx: error: Missing nullability on parameter `paramString` in method `getValue` [MissingNullability]
frameworks/base/core/java/android/app/DevInfoManager.java:xx: error: Missing nullability on parameter `paramString1` in method `update` [MissingNullability]
frameworks/base/core/java/android/app/DevInfoManager.java:xx: error: Missing nullability on parameter `paramString2` in method `update` [MissingNullability]
4 new API lint issues were found.
See tools/metalava/API-LINT.md for how to handle these.

另外构造方法也需要添加@hide进行保护。
进行上述修改后在源码根目录执行make update-api更新api文件后,进行编译即可。

app通过以下方式进行调用

DevInfoManager mDevInfoManager = (DevInfoManager) getSystemService(Context.DATA_SERVICE);
mDevInfoManager.xxxxx();

发表评论

CAPTCHAis initialing...