Ahao's Technical Blog Ahao's Technical Blog
首页
  • 001.基础篇
  • 002.玩转AOSP篇
  • 003.学穿Binder篇
  • 004.基础组件篇
  • 005.系统启动过程分析
  • 006.Hal开发入门与实践
  • 007.显示系统
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

阿豪讲Framework

不积跬步无以至千里
首页
  • 001.基础篇
  • 002.玩转AOSP篇
  • 003.学穿Binder篇
  • 004.基础组件篇
  • 005.系统启动过程分析
  • 006.Hal开发入门与实践
  • 007.显示系统
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 基础篇

  • 玩转AOSP篇

  • 学穿Binder篇

    • 000.Binder 专题导学 —— 如何深入掌握 Binder
    • 001.学习 Binder 的预备知识
    • 002.Binder 基本原理
    • 003.Binder 程序示例之 C 语言篇
    • 004.Binder 服务注册过程情景分析之 C 语言篇
    • 005.Binder 服务获取与使用过程情景分析之C语言篇
    • 006.Android Binder 驱动框架设计与分析
    • 007.Binder 驱动情景分析之 ServiceManager 启动过程
    • 008.Binder 驱动情景分析之服务注册过程
    • 009.Binder 驱动情景分析之服务获取与使用过程
    • 010.Binder 程序示例之 C++ 篇
    • 011.Binder C++ 程序分析之主要类解析
    • 012.Binder 服务注册过程情景分析之 C++ 篇
    • 013.Binder 服务获取与使用过程情景分析之C++篇
    • 014.Binder 程序示例之 aidl-cpp 篇
    • 015.添加 Android Native 系统服务
    • 016.添加 Native 系统服务回调
    • 017.Binder 程序示例之 Java 篇
    • 018.Binder Java 层初始化
    • 019.Binder Java 层服务注册过程分析
    • 020.Binder Java 层服务获取与使用过程分析
    • 021.添加 Java 系统服务
    • 022.Android Java 系统服务框架与第三方 App 使用自定义 Java 系统服务
    • 023.添加 Java 系统服务回调
    • 024.AIDL 数据类型详解之 Java 篇
      • AIDL 中的数据结构
      • Java 示例程序
      • 参考资料
    • 025.AIDL 数据类型详解之 C++ 篇
    • 026.Java 调用 Native 服务
    • 027.Native 调用 Java Binder 服务
    • 028.AIDL 关键字 in out inout oneway 解析
    • 029.Binder 驱动 Debug 入门指南
    • 030.Binder 匿名服务源码分析
    • 031.Binder 中的 Parcel 数据结构分析(C++)
    • 032.Binder 中的 Parcel 数据结构分析(Java)
    • 033.Binder 多线程情景分析
    • 034.Binder 线程池溢出问题
    • 035.Binder 代理对象泄露问题分析
    • 036.Binder 死亡通知情景分析
    • 037.Binder 异常处理机制
    • 038.Binder 系统源码演进
    • 039.Binder 面试题汇总
    • 补充——LocalService
  • 基础组件篇

  • 系统启动过程分析

  • Hal开发入门与实践

  • 显示系统

  • Framework
  • 学穿Binder篇
阿豪
2023-08-06
目录

024.AIDL 数据类型详解之 Java 篇

# AIDL 中的数据结构

在前 A面的示例中我们在 AIDL 文件中只使用了一些简单类型,实际上,在 Java 层,AIDL 支持以下多种数据类型:

  • Java 编程语言中的所有的基本类型(如 int、long、char、boolean 等)
  • String 与 CharSequence
  • List:List 中的所有元素必须是 AIDL 支持的数据类型,生成的方法旨在使用 List 接口,但另一方实际接收的具体类始终是 ArrayList
  • Map:Map 中的所有元素必须是 AIDL 支持的数据类型,不支持泛型 Map(如 Map<String,Integer> 形式的 Map),生成的方法旨在使用 Map 接口,但另一方实际接收的具体类始终是 HashMap
  • Parcelable 类型

Native 层支持类似的数据类型,这些类型与 Java 层的对应关系如下:

# Java 示例程序

接下来我们就来写一个演示 AIDL 数据类型的 Java 示例程序:

首先我们在 device/jelly/rice14/ 目录下创建如下的文件与文件夹

BinderJavaTypeDemo
├── Android.bp
└── com
    └── yuandaima
        ├── Client.java
        ├── HelloService.java
        ├── IHelloService.aidl
        ├── Server.java
        ├── Student.aidl
        └── Student.java
1
2
3
4
5
6
7
8
9
10

其中的 Student.aidl Student.java 是我们自定义的数据类型,在 AIDL 中自定义数据类型需要继承 Parcelable:

//Student.java

package com.yuandaima;

import android.os.Parcel;
import android.os.Parcelable;

public class Student implements Parcelable {
    int age;
    String name;

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(this.age);
        dest.writeString(this.name);
    }

    public Student() {
    }

    protected Student(Parcel in) {
        this.age = in.readInt();
        this.name = in.readString();
    }

    public static final Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() {
        @Override
        public Student createFromParcel(Parcel source) {
            return new Student(source);
        }

        @Override
        public Student[] newArray(int size) {
            return new Student[size];
        }
    };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

在 aidl 中我们只需要简单声明即可:

//Student.aidl
package com.yuandaima;

parcelable Student;
1
2
3
4

IHelloService.aidl 中声明了我们 binder 服务的对外接口:

package com.yuandaima;

import com.yuandaima.Student;

interface IHelloService
{
	void sayhello();
	int sayhello_to(String name);
	int printList(in List<String> strs);
	int printMap(in Map maps);
	int printStudent(in Student student);
}
1
2
3
4
5
6
7
8
9
10
11
12

接着我们编译 aidl 文件:

# 源码目录下
source build/envsetup.sh
# 选择合适的 product
lunch

# 进入项目目录下:
cd com/yuandaima
# -I 用于指定我们的在哪里查找 import
aidl -I .  IHelloService.aidl
1
2
3
4
5
6
7
8
9

编译后,就会生成对应的 Java 源文件 IHelloService.java。

接着编写服务端类 HelloService:

package com.yuandaima;

import android.os.RemoteException;
import android.util.Log;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class HelloService extends IHelloService.Stub {

    private static final String TAG = "HelloType";
    private int cnt1 = 0;
    private int cnt2 = 0;

    public void sayhello() throws android.os.RemoteException {
        cnt1++;
        Log.i(TAG, "sayhello : cnt = " + cnt1);
    }

    public int sayhello_to(java.lang.String name) throws android.os.RemoteException {
        cnt2++;
        Log.i(TAG, "sayhello_to " + name + " : cnt = " + cnt2);
        return cnt2;
    }

    public int printList(List<String> strs) throws android.os.RemoteException {

        for (int i = 0; i < strs.size(); i++) {
            Log.i(TAG, strs.get(i));
        }

        return 1;
    }

    @Override
    public int printMap(Map maps) throws RemoteException {


        Iterator entries = maps.entrySet().iterator();

        while (entries.hasNext()) {

            Map.Entry entry = (Map.Entry) entries.next();

            String key = (String) entry.getKey();

            String value = (String) entry.getValue();

            Log.i(TAG, "Key = " + key + ", Value = " + value);

        }

        return 1;
    }

    @Override
    public int printStudent(Student student) throws RemoteException {
        Log.d(TAG, "Student name " + student.name + "Student age" + student.age);
        return 1;
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

接着完成服务端程序 Server.java:

package com.yuandaima;

import android.util.Log;
import android.os.ServiceManager;

public class Server {

    private static final String TAG = "BinderServer";

    public static void main(String args[]) {
        /* add Service */
        Log.i(TAG, "add hello service");
        ServiceManager.addService("hello", new HelloService());

        //app_process 启动时,会启动 binder 线程用于获取和解析 binder 消息,应用程序无需关心
        while (true) {
            try {
            	Thread.sleep(100);
          	} catch (Exception e){}
        }   
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

接着完成客户端程序 Client.java:

package com.yuandaima;

import android.util.Log;
import android.os.ServiceManager;

import android.os.RemoteException;

import java.util.ArrayList;

import android.os.IBinder;

import java.util.HashMap;
import java.util.List;

public class Client {

    private static final String TAG = "BinderClient";

    public static void main(String args[])
    {
        
        /* 1. getService */
        IBinder binder = ServiceManager.getService("hello");
        
        if (binder == null)
        {
            Log.i(TAG, "can not get hello service");
            return;
        }

        IHelloService svr = IHelloService.Stub.asInterface(binder);
       
        try {
	        svr.sayhello();
	        Log.i(TAG, "call sayhello");
        } catch (Exception e) {

        }
           
        try {
	        int cnt = svr.sayhello_to("hello");
	    
	        Log.i(TAG, "call sayhello_to " + " : cnt = " + cnt);
        } catch (Exception e) {
            System.out.println("call sayhello_to , err :"+e);
            Log.i(TAG, "call sayhello_to , err : "+e);
        }


        try {
            List list = new ArrayList<String>();
            list.add("hello ");
            list.add("binder");
	        svr.printList(list);
	        Log.i(TAG, "call printlist");
        } catch (Exception e) {

        }

        try {
            HashMap map = new HashMap();
            map.put("Hello", "Map");
            svr.printMap(map);
            Log.i(TAG, "call printmap");
        } catch (Exception e) {

        }


        try {
            Student student = new Student();
            svr.printStudent(student);
            Log.i(TAG, "call printStudent");
        } catch (Exception e) {

        }
          
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

最后编译测试:

# 项目目录下执行单编
mm
# 回到系统源码目录
adb push out/target/product/rice14/system/framework/BinderTypeClient.jar /data/local/tmp

adb push out/target/product/rice14/system/framework/BinderTypeServer.jar /data/local/tmp

# 进入模拟器 shell 环境
adb shell
cd /data/local/tmp
export CLASSPATH=/data/local/tmp/BinderTypeClient.jar:/data/local/tmp/BinderTypeServer.jar

app_process /data/local/tmp  com.yuandaima.Server & 

app_process /data/local/tmp com.yuandaima.Client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

接着查看 Log:

logcat | grep HelloType   

08-06 17:43:55.343 10625 10635 I HelloType: sayhello : cnt = 1
08-06 17:43:55.343 10625 10635 I HelloType: sayhello_to hello : cnt = 1
08-06 17:43:55.344 10625 10635 I HelloType: hello 
08-06 17:43:55.344 10625 10635 I HelloType: binder
08-06 17:50:57.682 11488 11498 I HelloType: sayhello : cnt = 1
08-06 17:50:57.683 11488 11498 I HelloType: sayhello_to hello : cnt = 1
08-06 17:50:57.683 11488 11498 I HelloType: hello 
08-06 17:50:57.683 11488 11498 I HelloType: binder
08-06 17:50:57.683 11488 11498 I HelloType: Key = Hello, Value = Map
08-06 17:50:57.683 11488 11498 D HelloType: Student name nullStudent age0
1
2
3
4
5
6
7
8
9
10
11
12

# 参考资料

  • Android 接口定义语言 (AIDL) (opens new window)
  • Generating C++ Binder Interfaces with aidl-cpp (opens new window)
  • AIDL interface between Java and C++ (opens new window)
023.添加 Java 系统服务回调
025.AIDL 数据类型详解之 C++ 篇

← 023.添加 Java 系统服务回调 025.AIDL 数据类型详解之 C++ 篇→

最近更新
01
如何调试 SurfaceFlinger
10-05
02
SurfaceFlinger 概述
10-05
03
HWC 接口分析
10-05
更多文章>
Theme by Vdoing | Copyright © 2020-2025 AHao Framework | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式