在Android五层架构中,SystemService作为Android FW层中最核心的进程之一,掌握了大多数系统级服务的生死,例如PMS、AMS、WMS、DMS、TMS等。这些服务除了作为作为fw系统级服务的一部分之外,还能给上层app提供接口进行调用,例如三方应用可以通过pkms去安装应用,可以通过wms去弹出一个系统级对话框。

这里我们演示一个自定义这样的系统级服务,并且能向上给应用提供接口进行调用。在阅读本篇之前,可以先看看Android Framework 之 SystemServer进程_bpkeyattestationapplicationidprovider-CSDN博客

如下我们分为如下几个部分来介绍如何自定义系统级服务:

  • AIDL接口的定义
  • 服务端的实现和启动
  • 客户端的实现和注册
  • 回调接口的实现(Listener or Callback

一、自定义TinnoCanService服务

1、AIDL接口的定义

AIDL接口是android通用跨进程通信的工具之一,在Binder死磕到底(三):浅析AIDL-CSDN博客这篇文档中,我们深度解析了AIDL如何实现跨进程通信,以及它如何与binder架构进行对接。

因此任何JAVA进程(包括三方应用),都可以通过AIDL接口的方式来实现进程间通信。但是这里使用到AIDL的目的虽然也是跨进程通信,但是为什么会出现跨进程通信呢?

  • 首先我们的目的是为了实现一个系统级服务,那么假设这个服务和PMS这样的服务一样非常的重要,因此我们会把他放在framework层,并且很有可能与pms一样通过systemserver把他进行启动,可能通过创建进程一样启动也有可能直接启动。这里我们只讨论直接启动,因此这个服务所在的进程是systemserver。
  • 然后我们需要提供接口给上层应用,让三方应用能够像PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE)的方式获取到服务并进行调用。因此这里是三方应用去调用getSystemService方法,因此这段代码所处的进程是客户端应用进程。
  • 上面已经介绍了服务端进程为systemserver,客户端进程为上层应用,那么他们之间的通信,就需要通过AIDL。当然客户端上层应用可以直接集成AIDL接口直接调用,不需要通过getSystemService去进行中转,我们这里重点介绍getSystemService的方式。总之,无论那种方式,都需要通过AIDL来实现。这就是为什么需要AIDL的原因!

1)AIDL语法

其实这里我更推荐第二篇文档,这里针对第二篇文档做一个简单的总结:

A. 软件包与导入

每个 AIDL 文件都以一个可选软件包开头,该软件包与各个后端中的软件包名称相对应 

package my.package;

如需使用其他接口中定义的类型,必须先在构建系统中添加依赖项。在 cc_* 和 java_* Soong 模块中,.aidl 文件会直接在 Android 平台 build 中的 srcs 下使用,您可以使用 aidl: { include_dirs: ... } 这一字段添加目录。

import some.package.Foo;  // explicit import
import Foo;         // same as my.package.Foo
B. interface定义

AIDL 文件一般会定义用作接口的类型。以下是一个 AIDL 接口示例

interface ITeleport {
    // Location defined elsewhere
    void teleport(Location baz, float speed);
    String getName();
    // ITeleportCallback defined elsewhere
    void methodWithCallback(ITeleportCallback callback);
    // ITeleportSession defined elsewhere
    ITeleportSession getASubInterface();
}
//接口通过一系列方法定义对象。方法可以是 oneway (oneway void doFoo()),也可以是同步方法。
//如果某个接口被定义为 oneway (oneway interface ITeleport {...}),则该接口中的所有方法都隐式地带上 oneway。
//oneway方法会异步调度,并且无法返回结果。从同一线程到同一 binder 的单向方法也会按顺序执行(但可能会在不同线程上执行)。如需查看有关如何设置线程的讨论,请参阅 AIDL 后端线程管理。
//binder 允许通过 binder 接口共享多个接口和 binder 对象。AIDL 接口经常会在方法调用中使用回调,例如上例中的 ITeleportCallback。您可以在对同一方法的调用或对不同方法的调用之间重复使用回调对象。
//接口类型的另一个常见用途是从方法返回子接口或会话对象,例如前面示例中的 ITeleportSession。这种嵌套允许在 API 或根据运行时状态对不同的 API 进行封装。例如,会话可以代表对特定资源的所有权。
//当接口多次传递或返回到其来源客户端或服务器时,它们始终会保持底层绑定对象的指针相等性。
//方法可以有零个或多个参数。方法的参数可以是 in、out 或 inout。如需查看有关这会如何影响参数类型的讨论,请参阅 AIDL 后端方向性。
C. Parcelable序列化数据结构

本质还是一种数据类型。Android 10 及更高版本支持直接使用 AIDL 进行 Parcelable 定义。这种类型的 Parcelable 称为结构化 Parcelable。如需详细了解结构化 AIDL 和稳定的 AIDL 在 AIDL 编译器和我们的构建系统中的关系,请参阅​​​​​​结构化 AIDL 与稳定的 AID

package my.package;
import my.package.Boo;
parcelable Baz {
    @utf8InCpp String name = "baz";
    Boo boo;
}
D. 其他数据类型

AIDL接口中也可以定义常量/枚举/联合体

//联合体
package my.package;
import my.package.FooSettings;
import my.package.BarSettings;
union Settings {
    FooSettings fooSettings;
    BarSettings barSettings;
    @utf8InCpp String str;
    int number;
}
//枚举
package my.package;
enum Boo {
    A = 1 * 4,
    B = 3,
}
//常量
const @utf8InCpp String HAPPY = ":)";
const String SAD = ":(";
const byte BYTE_ME = 1;
const int ANSWER = 6 * 7;
E. 方法参数(非常重要)

您可以将 aidl 编译器视为类型的参考实现。 在创建接口时,请调用如下命令

#在创建接口时,请调用如下命令来查看生成的接口文件
aidl --lang=<backend> ... 
#在使用 aidl_interface 模块时,您可以在如下目录查看输出
out/soong/.intermediates/<path to module>/

其他语法请详细阅读官方文档。。。

2)ITinnoCanManager.aidl创建

接下来我们第一步需要创建AIDL接口文件,那么这个文件放在哪里呢?这里参考IUsageStatsManager.aidl文件在aosp/frameworks/base/core/java/android/app/can

如上创建了两个aidl文件,其中ITinnoManager.aidl作为主接口,ICanDataListener.aidl作为被ITinnoManager.aidl引用的回调接口,后续详细介绍回调接口。

A. 为什么选择/aosp/frameworks/base/core/java/android/app/can目录呢?

Android 永乐大典之framework.jar中已经提到,Android源码根目录的fameworks目录下的比较重要的两个jar包:framework.jar和services.jar

其中framework.jar包核心内容之一为API的实现,适用于应用层接口扩展。即上层应用可以通过集成framework.jar来达到直接调用系统api的方式。因此我们这里加的IXXX.aidl接口最终是提供给上层应用使用,因此需要编译进framework.jar中。

B. framework.jar编译架构

framwork.jar为framework/base目录下的Android.bp编译,目录架构如下:

├frameworks/base
├── Android.bp
├── Android.mk
├── core
│   ├── java
│   │   ├── android
│   │   │   ├── content
│   │   │   │   ├── Context.java
│   │   │   ├── app
│   │   │   │   ├── SystemServiceRegistry.java
│   │   │   │   ├── can
│   │   │   │   │   ├── ICanDataListener.aidl
│   │   │   │   │   ├── ITinnoCanManager.aidl
│   │   │   │   │   └── TinnoCanManager.java
│   │   │   │   ├── usage
│   │   │   │   │   ├── ExternalStorageStats.aidl
│   │   │   │   │   ├── ExternalStorageStats.java
│   │   │   │   │   ├── ICacheQuotaService.aidl
│   │   │   │   │   ├── IStorageStatsManager.aidl
│   │   │   │   │   ├── IUsageStatsManager.aidl
│   │   │   │   │   ├── OWNERS
│   │   │   │   │   ├── PackageUsageStats.aidl
│   │   │   │   │   ├── StorageStats.aidl
│   │   │   │   │   ├── StorageStats.java
│   │   │   │   │   ├── StorageStatsManager.java
│   │   │   │   │   ├── UsageEvents.aidl
│   │   │   │   │   ├── UsageEvents.java
│   │   │   │   │   ├── UsageStats.java
│   │   │   │   │   └── UsageStatsManager.java
│   │   │   │   ├── IApplicationStartInfoCompleteListener.aidl
│   │   │   │   ├── IApplicationThread.aidl
│   │   │   │   ├── IAppTask.aidl
│   │   │   │   ├── IAppTraceRetriever.aidl
│   │   │   │   ├── IAssistDataReceiver.aidl
│   │   │   │   ├── IBackupAgent.aidl
│   │   │   │   ├── ICompatCameraControlCallback.aidl

从android.bp的依赖关系来看:

  • AOSP/framework/base/Android.bp:集成core/java,其中core目录下包含(api  java  jni  proto  res  sysprop)
  • AOSP/framework/base/core/java/Android.bp:集成子目录所有的aidl和java文件另外

  • AOSP/frameworks/base/core/java/android/app:此目录存放了很多aidl接口,另外还讲关联的放在文件夹里面,因此我们自定义的时候也可以在这里创建目录专门放我们新加的接口和XXXManager.java

3)Context.java新增服务

AIDL接口定义好之后,我们需要在Context里面声明一个新的服务,正是因为这个声明,我们才能在后续开发过程中,绑定服务端,绑定客户端,给上层应用提供 getSystemService(Context.XXXSERVICE)。

在aosp/frameworks/base/core/java/android/content/Context.java配置如下:

2、TinnoCanService服务实现

前文定义了aidl接口,那么接下来的就需要我们分别在服务端和客户端来实现改接口。这里先介绍一下服务端进程XXXService如何实现与启动。

1)service.jar的编译

├frameworks/base/services
├── Android.bp
├── can
│   ├── Android.bp
│   ├── java
│   │   └── com
│   │       └── android
│   │           └── server
│   │               └── can
│   │                   └── TinnoCanService.java
│   └── OWNERS
├── usage
│   ├── Android.bp
│   ├── java
│   │   └── com
│   │       └── android
│   │           └── server
│   │               └── usage
│   │                   ├── UsageStatsShellCommand.java
│   │                   ├── UsageStatsXml.java
│   │                   ├── UsageStatsXmlV1.java
│   │                   ├── UserBroadcastEvents.java
│   │                   ├── UserBroadcastResponseStats.java
│   │                   └── UserUsageStatsService.java
│   └── OWNERS

参考aosp原生逻辑,我们也可以想usage一样,在frameworks/base/services/目录下面加一个can目录,然后在can里面写入Android.bp

//frameworks/base/services/can/Android.bp
package {
    // See: http://go/android-license-faq
    // A large-scale-change added 'default_applicable_licenses' to import
    // all of the 'license_kinds' from "frameworks_base_license"
    // to get the below license kinds:
    //   SPDX-license-identifier-Apache-2.0
    default_applicable_licenses: ["frameworks_base_license"],
}
//编译can目录下面的java文件,命名services.can-sources
filegroup {
    name: "services.can-sources",
    srcs: ["java/**/*.java"],
    path: "java",
    visibility: ["//frameworks/base/services"],
}
//把services.can-sources打包为静态库
java_library_static {
    name: "services.can",
    defaults: ["platform_service_defaults"],
    srcs: [":services.can-sources"],
    libs: ["services.core"],
}

然后在上一级目录frameworks/base/services/Android.bp中加入如上定义的services.can和services.can-sources:

filegroup {
    name: "services-non-updatable-sources",
    srcs: [
        ":services.core-sources",
        ":services.core-sources-am-wm",
        "core/java/com/android/server/am/package.html",
        ":services.texttospeech-sources",
        ":services.usage-sources",
        ":services.can-sources",  //引入自定义的services.can-sources
        ":services.usb-sources",
        ":services.voiceinteraction-sources",
        ":services.wallpapereffectsgeneration-sources",
        ":services.wifi-sources",
    ],
    visibility: ["//visibility:private"],
}
    // The convention is to name each service module 'services.$(module_name)'
    static_libs: [
        "services.core",
        "services.accessibility",
        "services.appprediction",
        "services.appwidget",
        "services.translation",
        "services.texttospeech",
        "services.usage",
        "services.can",     //引入自定义的静态库services.can
        "services.usb",
        "services.voiceinteraction",
        "services.wallpapereffectsgeneration",
        "services.wifi",
        "service-blobstore",
        "service-jobscheduler",
        "android.hidl.base-V1.0-java",
    ],

2)TinnoCanService服务端实现

A. 继承SystemService

这里定义的TinnoCanService继承了SystemService,所以他的生命周期已经和系统级服务一致,并且通过父类的方法可以得到onBootPhase等这些回调来监听system server进程启动服务的阶段。

重写onStart方法,可以进行系统级服务的启动或者初始化,通常这里需要注册aidl接口到service manager中,这部分逻辑可以参考Binder机制详解-CSDN博客

B. AIDL接口本地stub实现

publishBinderService向binder核心进程service manager注册服务的时候,需要传递IXXX.Stub类进去,注意这里只是一个单纯的对象,所以她是一个客体资源,在后文selinux章节中额外针对她有说明。

C. AIDL回调接口/监听器

前面的接口的方向:客户端 ---->服务端 ;那么服务端TinnoCanService想主动回调给客户端呢?那么就需要通过监听器或者回调接口来实现,其实本质是一样,只是名字不同。在AIDL中我们已经定义了,如下:

在TinnoCanService里面我们通常只需要维护一个监听器列表,然后有需要的时候主动回调监听器的方法,如下示例:

public class TinnoCanService extends SystemService {
    static final String TAG = "TinnoCanService";
    // CAN FW Service Context
    private Context mContext = null;
    // CAN FW/APP listener list
    private ArrayList<ICanDataListener> dataListener = new ArrayList();
    public TinnoCanService(Context context) {
        super(context);
        mContext = context;
    }
    @Override
    public void onStart() {
        Slog.d(TAG, "onStart");
        publishBinderService(Context.TINNO_CAN_SERVICE, new BinderService());
    }
    private final class BinderService extends ITinnoCanManager.Stub {
        //添加监听器
        public void addCanDataListener(ICanDataListener listener) {
            Slog.d(TAG, "APP call to method #addCanDataListener");
            if (!dataListener.contains(listener)) {
                dataListener.add(listener);
                Slog.d(TAG, "addCanDataListener success: list is " + dataListener.size());
            } else {
                Slog.e(TAG, "addCanDataListener failed: It already exists");
            }
        }
        //移除监听器
        public void removeCanDataListener(ICanDataListener listener) {
            Slog.d(TAG, "APP call to method #removeCanDataListener");
            if(dataListener.contains(listener)) {
                dataListener.remove(listener);
                Slog.d(TAG, "removeCanDataListener success: list is " + dataListener.size());
            } else {
                Slog.e(TAG, "removeCanDataListener failed: It doesn't exist");
            }
        }
        // FW收到来自HAL层的数据回调,递归到APP注册上来的所有监听器
        public void receiveCanData(byte channel, byte format, byte rtr, int cob_id, byte dlc, byte[] bytes){
            Slog.d(TAG, "FW call to method #receiveCanData, list is " + dataListener.size());
            Iterator<ICanDataListener> it = dataListener.iterator();
            while(it.hasNext()) {
                boolean isDied = false;
                ICanDataListener item = it.next();
                try {
                    Slog.d(TAG, "FW call to method #onReceiveCanData");
                    item.onReceiveCanData(channel, format, rtr, cob_id, dlc, bytes);
                } catch (RemoteException e) { //DeadObjectException 是RemoteException子类
                    isDied = true;
                    Slog.e(TAG, "FW call to method #onReceiveCanData Exception and isDied", e);
                } catch (Exception e) {
                    Slog.e(TAG, "FW call to method #onReceiveCanData Exception", e);
                } finally {
                    if (isDied) {
                        Slog.d(TAG, "FW call to method #onReceiveCanData remove listener");
                        it.remove();
                        isDied = false;
                    }
                }
            }
        }
    }
}

3)TinnoCanService服务的启动

最后在SystemServer里面启动服务,位置可以任意定,实现开机自启动

3、TinnoCanManager客户端代理

前文定义了aidl接口,那么接下来的就需要我们分别在服务端和客户端来实现改接口。这里先介绍一下客户端代理对象XXXManager如何实现?

1)TinnoCanManager实现

TinnoCanManager.java的实现同aosp其他服务一样,可以和ITinnoCanManager.aidl同级目录下,这里我把他们放到一起。如下实现:

package android.app.can;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.annotation.SystemService;
import android.os.RemoteException;
import android.content.Context;
import android.util.CloseGuard;
import android.util.Log;
import android.util.Slog;
import java.util.concurrent.Executor;
@SystemService(Context.TINNO_CAN_SERVICE)
public final class TinnoCanManager implements AutoCloseable {
    static final String TAG = "TinnoCanManager";
    @UnsupportedAppUsage
    private final Context mContext;
    @UnsupportedAppUsage
    private final ITinnoCanManager mService;
    /**
     * {@hide}
     */
    public TinnoCanManager(Context context, ITinnoCanManager service) {
        mContext = context;
        mService = service;
        Slog.e(TAG, "----------------SHEN: TinnoCanManager 构造方法");
    }
    public void init() {
        Slog.e(TAG, "----------------SHEN: TinnoCanManager.init");
        try{
            if (mService != null) {
                mService.init();
            }
        } catch (RemoteException e) {
            // fallthrough and return the empty list.
        }
    }
    public void deinit() {
        Slog.e(TAG, "----------------SHEN: TinnoCanManager.deinit");
        try{
            mService.deinit();
        } catch (RemoteException e) {
            // fallthrough and return the empty list.
        }
    }
    public void config(int channel, int baud_rate) {
        Slog.e(TAG, "----------------SHEN: TinnoCanManager.config channel="+channel+" baud_rate="+baud_rate);
        try{
            mService.config(channel,baud_rate);
        } catch (RemoteException e) {
            // fallthrough and return the empty list.
        }
    }
    /** {@hide} */
    public void addCanDataListener(@NonNull ICanDataListener listener) {
        Slog.e(TAG, "----------------SHEN: TinnoCanManager.addCanDataListener");
        try{
            mService.addCanDataListener(listener);
        } catch (RemoteException e) {
            // fallthrough and return the empty list.
        }
    }
    /** {@hide} */
    public void removeCanDataListener(@NonNull ICanDataListener listener) {
        Slog.e(TAG, "----------------SHEN: TinnoCanManager.removeCanDataListener");
        try{
            mService.removeCanDataListener(listener);
        } catch (RemoteException e) {
            // fallthrough and return the empty list.
        }
    }
    public void sendCanData(int channel, int format, int rtr, int cob_id, @NonNull byte []data, int len) {
        Slog.e(TAG, "----------------SHEN: TinnoCanManager.sendCanData");
        try{
            mService.sendCanData(channel, format, rtr, cob_id, data, len);
        } catch (RemoteException e) {
            // fallthrough and return the empty list.
        } 
    }
    private final CloseGuard guard = new CloseGuard();
    public void start() {
        Slog.e(TAG, "----------------SHEN: TinnoCanManager.start");
        try{
            guard.open("can");
            mService.start();
        } catch (RemoteException e) {
            // fallthrough and return the empty list.
        }
    }
    public void stop() {
        Slog.e(TAG, "----------------SHEN: TinnoCanManager.stop");
           try{
            mService.stop();
            guard.close();
        } catch (RemoteException e) {
            // fallthrough and return the empty list.
        }
    }
    @Override
    public void close() {
    }
}

其中比较重要的地方总结如下:

A. Context.TINNO_CAN_SERVICE关联

B. mService的持有

C. 监听器/回调接口的注册

在TinnoCanManager里面实现监听器或者回调接口的注册与移除,其本质就是把IXXXListener或者IXXXCallback作为binder序列化数据传递到服务端,来进行通信

2)SystemServiceRegistry注册

最后一步就是通过SystemServiceRegistry来关联TinnoCanManager和TinnoCanService,如下核心代码为IXXX.Stub.asInterface,详细机制请SystemServiceRegistry绑定服务

二、APP的调用

    

第一章已经在framework层搭建好了服务和代理。那么本章讲介绍APP层如何来进行调用。大概流程如下:

  • 引入famework.jar包
  • 调用AIDL中定义的接口
  • 注册AIDL中的回调接口

1、FW侧编译famework.jar

第一章实现的TinnoCanManager和TinnoCanService都在framework/base中,其中framework.jar为什么非常重要,因为她主要编译了系统的通用接口。同样,上层app想直接引用fw层的api或者方法,那么必须要通过framework.jar来实现。

因此这里遇到第一个问题,就是我们如何把framework.jar生成和应用如何集成framwork.jar。

注意,经过验证得出如下两条结论:

  • 单编Framework或者全编System在out\target\product\qssi\system\framework目录下面的framwork.jar其实是无法给app直接进行使用的。
  • 单编Framework或者全编System在out\target\common\obj\JAVA_LIBRARIES\framework_intermediates目录下面默认只生成了classes-header.jar文件,此文件也是无法直接提供给app进行使用。

那么解决方案如下:

source build/envsetup.sh
lunch xxx
#生成完整的framework.jar
make javac-check-framework

如上命令执行成功会在out\target\common\obj\JAVA_LIBRARIES\framework_intermediates路径下生成classes.jar

2、APP侧导入famework.jar

如上编译出了famework.jar,那么我们需要把这个包导入到我们的普通应用里面,如何引入呢?

跟普通的jar引入一致,首先需要在app目录下建立一个libs目录,用来专门存放前文编译的xxx.jar,可以重命名,然后只需要在dependencies里面进行配置即可,这里介绍两个build.gradle版本:

  • 普通版的build.gradle

  • 升级版的build.gradle.kts:

3、APP调用AIDL普通接口

如上导入我们编译的xxx.jar之后,在as里面就可以直接索引到这个对象。因此这里直接通过getSystemService获取服务客户端Manager,其中getSystemService有几个重载函数:

即我们可以直接传递XXXManager.class,也可以直接传递一个字符串,通常一般传递Context.XXX,但是Context并没有包含在framework.jar里面,所以这里索引不到Context对象,那么可以直接传递服务字符串即可。

通过如上的原理,我们在普通应用中编写如下代码:

package com.example.myapplication;
import android.app.can.TinnoCanManager;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
    private TinnoCanManager mCanManager = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        mCanManager = (TinnoCanManager) getSystemService("tinno_can");
        if (mCanManager == null) {
            Log.e("SHEN","TINNO CAN MANAGER IS NULL");
        } else {
            Log.e("SHEN","TINNO CAN MANAGER IS OK");
            mCanManager.init();
            mCanManager.start();
            mCanManager.sendCanData(1,1,1,1,new byte[]{0x01,0x01,0x01,0x00,0x00},5);
        }
    }
}

如上代码通过getSystemService获取自定义XXXManager,然后直接调用他的普通接口,注意这些接口在XXXManager.java的定义里面都没有用hide进行修饰,所以如上直接调用init/start/sendCanData几个接口,日志打印如下:

4、APP调用AIDL回调接口

在A14中,AIDL中的特殊接口,例如方法名称包含Listener的话,会被编译系统强制要求带上hide修饰,如下:

针对这类接口,普通应用无法调用,可以通过接口装饰或者适配的方式进行规避,或者参考本篇第三章内容,把普通应用进行平台签名。

三、踩过的坑

1、frameworks/base/api:api-stubs-docs-non-updatable check current API 

A. 报错日志

该报错表明您修改了Android框架中已批准的API接口,但未同步更新API文档文件(current.txt/removed.txt),导致编译时出现API一致性校验失败

Android对公开API有严格管控,任何修改(新增/删除/变更)都需要同步更新frameworks/base/api/current.txt文件以保持文档一致性。该文件记录了所有公开API的签名信息。

提供两种解决方法:

  • 方法一:将新增/修改的API标记为非公开接口(仅供系统内部使用),避免纳入公共API文档。 /** * @hide */ public void newMethod() {    ...   }
  • 方法二:通过m api-stubs-docs-non-updatable-update-current-api命令自动更新current.txt文件
******************************
You have tried to change the API from what has been previously approved.
 
To make these errors go away, you have two choices:
1.  You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)
to the new methods, etc. shown in the above diff.
 
2.  You can update current.txt and/or removed.txt by executing the following command:
m api-stubs-docs-non-updatable-update-current-api
 
To submit the revised current.txt to the main Android repository,
you will need approval.
******************************

B. 解决方案

如上报错日志已经明确提示,current.txt文件不允许我们手动去修改,我们可以通过m api-stubs-docs-non-updatable-update-current-api命令去自动生成,执行如下命令

source build/envsetup.sh
lunch xxx
cd framework/base
m api-stubs-docs-non-updatable-update-current-api

2、APP运行时因为hidden method导致程序CRASH

A. 报错日志

关键日志Accessing hidden method Landroid/app/can/TinnoCanManager;->addCanDataListener(Landroid/app/can/ICanDataListener;)V (blocked, linking, denied)表示此接口的方法被hide注释,那么普通三方应用调用addCanDataListener时无法找到此方法,因此出现了运行时程序崩溃。

B. 原因分析

C. 解决方案

针对hide声明的方法,不允许外部apk调用,需要放进源码中编译对其进行系统签名:LOCAL_CERTIFICATE := platform 

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := TaskViewC
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := app-debug.apk
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := platform 
LOCAL_DEX_PREOPT := false
LOCAL_PRIVILEGED_MODULE := true
include $(BUILD_PREBUILT)

3、APP运行时Outgoing transactions from this process must be FLAG_ONEWAY

A. 报错日志

如下关键日志Outgoing transactions from this process must be FLAG_ONEWAY,表明跨进程通信时未设置单向传输标志。

06-02 15:35:38.522  2059  2447 D TinnoCanService: FW call to method #onReceiveCanData
06-02 15:35:38.523  2059  2447 E Binder  : Outgoing transactions from this process must be FLAG_ONEWAY
06-02 15:35:38.523  2059  2447 E Binder  : java.lang.Throwable
06-02 15:35:38.523  2059  2447 E Binder  : 	at android.os.BinderProxy.transact(BinderProxy.java:541)
06-02 15:35:38.523  2059  2447 E Binder  : 	at android.app.can.ICanDataListener$Stub$Proxy.onReceiveCanData(ICanDataListener.java:135)
06-02 15:35:38.523  2059  2447 E Binder  : 	at com.android.server.can.TinnoCanService$CanFWServiceWrapper.receiveCanData(TinnoCanService.java:299)
06-02 15:35:38.523  2059  2447 E Binder  : 	at com.android.server.can.TinnoCanService$CanHalServiceWrapper$1.Datareport(TinnoCanService.java:111)
06-02 15:35:38.523  2059  2447 E Binder  : 	at vendor.tinno.can_test.V1_0.IDataCallback$Stub.onTransact(IDataCallback.java:533)

B. 解决方案

4、ServiceManager.add出现Selinux权限异常

01-03 06:02:58.330  9505  9505 I SystemServiceManager: Starting com.android.server.usage.UsageStatsService
01-03 06:02:58.337  9505  9505 V SystemServerTiming: StartUsageService took to complete: 7ms
01-03 06:02:58.337  9505  9505 D SystemServerTiming: StartTinnoCanService
01-03 06:02:58.337  9505  9505 E SystemServer: ----------------SHEN: startService TINNO_CAN_SERVICE start
01-03 06:02:58.338  9505  9505 I SystemServiceManager: Starting com.android.server.can.TinnoCanService
01-03 06:02:58.338  9505  9505 D TinnoCanService: onStart
01-03 06:02:58.340  9505  9505 E System  : ******************************************
01-03 06:02:58.340  9505  9505 E System  : ************ Failure starting system services
01-03 06:02:58.340  9505  9505 E System  : java.lang.RuntimeException: Failed to start service com.android.server.can.TinnoCanService: onStart threw an exception
01-03 06:02:58.340  9505  9505 E System  :      at com.android.server.SystemServiceManager.startService(SystemServiceManager.java:257)
01-03 06:02:58.340  9505  9505 E System  :      at com.android.server.SystemServiceManager.startService(SystemServiceManager.java:233)
01-03 06:02:58.340  9505  9505 E System  :      at com.android.server.SystemServer.startCoreServices(SystemServer.java:1370)
01-03 06:02:58.340  9505  9505 E System  :      at com.android.server.SystemServer.run(SystemServer.java:946)
01-03 06:02:58.340  9505  9505 E System  :      at com.android.server.SystemServer.main(SystemServer.java:669)
01-03 06:02:58.340  9505  9505 E System  :      at java.lang.reflect.Method.invoke(Native Method)
01-03 06:02:58.340  9505  9505 E System  :      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
01-03 06:02:58.340  9505  9505 E System  :      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:955)
01-03 06:02:58.340  9505  9505 E System  : Caused by: java.lang.SecurityException: SELinux denied.
01-03 06:02:58.340  9505  9505 E System  :      at android.os.Parcel.createExceptionOrNull(Parcel.java:3057)
01-03 06:02:58.340  9505  9505 E System  :      at android.os.Parcel.createException(Parcel.java:3041)
01-03 06:02:58.340  9505  9505 E System  :      at android.os.Parcel.readException(Parcel.java:3024)
01-03 06:02:58.340  9505  9505 E System  :      at android.os.Parcel.readException(Parcel.java:2966)
01-03 06:02:58.340  9505  9505 E System  :      at android.os.IServiceManager$Stub$Proxy.addService(IServiceManager.java:468)
01-03 06:02:58.340  9505  9505 E System  :      at android.os.ServiceManagerProxy.addService(ServiceManagerNative.java:72)
01-03 06:02:58.340  9505  9505 E System  :      at android.os.ServiceManager.addService(ServiceManager.java:213)
01-03 06:02:58.340  9505  9505 E System  :      at com.android.server.SystemService.publishBinderService(SystemService.java:567)
01-03 06:02:58.340  9505  9505 E System  :      at com.android.server.SystemService.publishBinderService(SystemService.java:551)
01-03 06:02:58.340  9505  9505 E System  :      at com.android.server.SystemService.publishBinderService(SystemService.java:538)
01-03 06:02:58.340  9505  9505 E System  :      at com.android.server.can.TinnoCanService.onStart(TinnoCanService.java:61)
01-03 06:02:58.340  9505  9505 E System  :      at com.android.server.SystemServiceManager.startService(SystemServiceManager.java:255)
01-03 06:02:58.340  9505  9505 E System  :      ... 7 more
01-03 06:02:58.340  9505  9505 V SystemServerTiming: StartTinnoCanService took to complete: 3ms
01-03 06:02:58.341  9505  9505 E Zygote  : System zygote died with fatal exception
01-03 06:02:58.341  9505  9505 E Zygote  : java.lang.RuntimeException: Failed to start service com.android.server.can.TinnoCanService: onStart threw an exception
01-03 06:02:58.341  9505  9505 E Zygote  :      at com.android.server.SystemServiceManager.startService(SystemServiceManager.java:257)
01-03 06:02:58.341  9505  9505 E Zygote  :      at com.android.server.SystemServiceManager.startService(SystemServiceManager.java:233)
01-03 06:02:58.341  9505  9505 E Zygote  :      at com.android.server.SystemServer.startCoreServices(SystemServer.java:1370)
01-03 06:02:58.341  9505  9505 E Zygote  :      at com.android.server.SystemServer.run(SystemServer.java:946)
01-03 06:02:58.341  9505  9505 E Zygote  :      at com.android.server.SystemServer.main(SystemServer.java:669)
01-03 06:02:58.341  9505  9505 E Zygote  :      at java.lang.reflect.Method.invoke(Native Method)
01-03 06:02:58.341  9505  9505 E Zygote  :      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
01-03 06:02:58.341  9505  9505 E Zygote  :      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:955)
01-03 06:02:58.341  9505  9505 E Zygote  : Caused by: java.lang.SecurityException: SELinux denied.
01-03 06:02:58.341  9505  9505 E Zygote  :      at android.os.Parcel.createExceptionOrNull(Parcel.java:3057)
01-03 06:02:58.341  9505  9505 E Zygote  :      at android.os.Parcel.createException(Parcel.java:3041)
01-03 06:02:58.341  9505  9505 E Zygote  :      at android.os.Parcel.readException(Parcel.java:3024)
01-03 06:02:58.341  9505  9505 E Zygote  :      at android.os.Parcel.readException(Parcel.java:2966)
01-03 06:02:58.341  9505  9505 E Zygote  :      at android.os.IServiceManager$Stub$Proxy.addService(IServiceManager.java:468)
01-03 06:02:58.341  9505  9505 E Zygote  :      at android.os.ServiceManagerProxy.addService(ServiceManagerNative.java:72)
01-03 06:02:58.341  9505  9505 E Zygote  :      at android.os.ServiceManager.addService(ServiceManager.java:213)
01-03 06:02:58.341  9505  9505 E Zygote  :      at com.android.server.SystemService.publishBinderService(SystemService.java:567)
01-03 06:02:58.341  9505  9505 E Zygote  :      at com.android.server.SystemService.publishBinderService(SystemService.java:551)
01-03 06:02:58.341  9505  9505 E Zygote  :      at com.android.server.SystemService.publishBinderService(SystemService.java:538)
01-03 06:02:58.341  9505  9505 E Zygote  :      at com.android.server.can.TinnoCanService.onStart(TinnoCanService.java:61)
01-03 06:02:58.341  9505  9505 E Zygote  :      at com.android.server.SystemServiceManager.startService(SystemServiceManager.java:255)
01-03 06:02:58.341  9505  9505 E Zygote  :      ... 7 more
01-03 06:02:58.341  9505  9505 D AndroidRuntime: Shutting down VM
01-03 06:02:58.341  9505  9505 E AndroidRuntime: *** FATAL EXCEPTION IN SYSTEM PROCESS: main
01-03 06:02:58.341  9505  9505 E AndroidRuntime: java.lang.RuntimeException: Failed to start service com.android.server.can.TinnoCanService: onStart threw an exception
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at com.android.server.SystemServiceManager.startService(SystemServiceManager.java:257)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at com.android.server.SystemServiceManager.startService(SystemServiceManager.java:233)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at com.android.server.SystemServer.startCoreServices(SystemServer.java:1370)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at com.android.server.SystemServer.run(SystemServer.java:946)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at com.android.server.SystemServer.main(SystemServer.java:669)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at java.lang.reflect.Method.invoke(Native Method)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:955)
01-03 06:02:58.341  9505  9505 E AndroidRuntime: Caused by: java.lang.SecurityException: SELinux denied.
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at android.os.Parcel.createExceptionOrNull(Parcel.java:3057)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at android.os.Parcel.createException(Parcel.java:3041)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at android.os.Parcel.readException(Parcel.java:3024)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at android.os.Parcel.readException(Parcel.java:2966)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at android.os.IServiceManager$Stub$Proxy.addService(IServiceManager.java:468)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at android.os.ServiceManagerProxy.addService(ServiceManagerNative.java:72)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at android.os.ServiceManager.addService(ServiceManager.java:213)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at com.android.server.SystemService.publishBinderService(SystemService.java:567)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at com.android.server.SystemService.publishBinderService(SystemService.java:551)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at com.android.server.SystemService.publishBinderService(SystemService.java:538)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at com.android.server.can.TinnoCanService.onStart(TinnoCanService.java:61)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        at com.android.server.SystemServiceManager.startService(SystemServiceManager.java:255)
01-03 06:02:58.341  9505  9505 E AndroidRuntime:        ... 7 more
01-03 06:02:58.345  9505  9505 E SystemServiceRegistry: No service published for: dropbox
01-03 06:02:58.345  9505  9505 E SystemServiceRegistry: android.os.ServiceManager$ServiceNotFoundException: No service published for: dropbox
01-03 06:02:58.345  9505  9505 E SystemServiceRegistry:         at android.os.ServiceManager.getServiceOrThrow(ServiceManager.java:166)
01-03 06:02:58.345  9505  9505 E SystemServiceRegistry:         at android.app.SystemServiceRegistry$25.createService(SystemServiceRegistry.java:494)
01-03 06:02:58.345  9505  9505 E SystemServiceRegistry:         at android.app.SystemServiceRegistry$25.createService(SystemServiceRegistry.java:491)
01-03 06:02:58.345  9505  9505 E SystemServiceRegistry:         at android.app.SystemServiceRegistry$CachedServiceFetcher.getService(SystemServiceRegistry.java:2000)
01-03 06:02:58.345  9505  9505 E SystemServiceRegistry:         at android.app.SystemServiceRegistry.getSystemService(SystemServiceRegistry.java:1674)
01-03 06:02:58.345  9505  9505 E SystemServiceRegistry:         at android.app.ContextImpl.getSystemService(ContextImpl.java:2212)
01-03 06:02:58.345  9505  9505 E SystemServiceRegistry:         at android.content.Context.getSystemService(Context.java:4422)
01-03 06:02:58.345  9505  9505 E SystemServiceRegistry:         at com.android.server.am.ActivityManagerService.addErrorToDropBox(ActivityManagerService.java:9388)
01-03 06:02:58.345  9505  9505 E SystemServiceRegistry:         at com.android.server.am.ActivityManagerService.handleApplicationCrashInner(ActivityManagerService.java:8992)
01-03 06:02:58.345  9505  9505 E SystemServiceRegistry:         at com.android.server.am.ActivityManagerService.handleApplicationCrash(ActivityManagerService.java:8885)
01-03 06:02:58.345  9505  9505 E SystemServiceRegistry:         at com.android.internal.os.RuntimeInit$KillApplicationHandler.uncaughtException(RuntimeInit.java:160)
01-03 06:02:58.345  9505  9505 E SystemServiceRegistry:         at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1071)
01-03 06:02:58.345  9505  9505 E SystemServiceRegistry:         at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1066)
01-03 06:02:58.345  9505  9505 E SystemServiceRegistry:         at java.lang.Thread.dispatchUncaughtException(Thread.java:2306)
01-03 06:02:58.346  9505  9505 E SystemServiceRegistry: Manager wrapper not available: dropbox

如上日志,systemserver在向系统注册自定义服务的时候,会出现主动抛出异常:

publishBinderService(注册服务)-→ServiceManager.add(向service manager进程注册服务)。就是这个地方,详细流程分析请参考https://blog.csdn.net/qq_27672101/article/details/136746558

其原因是在向Service Manager注册或查询系统的时候,要求开发者必须为服务定义‌专属上下文(如system_xxx_service),而非复用默认的通用类型。因此我们第一步就需要给新增的TinnoCanService添加专属的scontext上下文

最后权限问题可以参考https://blog.csdn.net/qq_27672101/article/details/107720990

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐