我是靠谱客的博主 现代大山,最近开发中收集的这篇文章主要介绍Android Binder机制分析(4) Parcel类分析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

引言

在上一篇Blog中,在分析服务注册过程时,往data(Parcel对象)变量写入数据时,有这样的调用路径:

BpServiceManager::addService()–>Parcel::writeStrongBinder()–>flatten_binder()–>finish_flatten_binder()

由于finish_flatten_binder()方法中涉及到的东西太多,在上一篇博客就没有展开来讲。这篇博客将详细分析数据是如何写入到data中的。

下面是Parcel类的定义:

Parcel.h
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
class Parcel
{
public:

Parcel();

~Parcel();


const uint8_t*
data() const;

size_t
dataSize() const;

size_t
dataAvail() const;

size_t
dataPosition() const;

size_t
dataCapacity() const;


status_t
setDataSize(size_t size);

void
setDataPosition(size_t pos) const;

status_t
setDataCapacity(size_t size);


status_t
setData(const uint8_t* buffer, size_t len);


status_t
appendFrom(Parcel *parcel, size_t start, size_t len);


bool
hasFileDescriptors() const;


status_t
writeInterfaceToken(const String16& interface);

bool
enforceInterface(const String16& interface) const;

bool
checkInterface(IBinder*) const;


void
freeData();


const size_t*
objects() const;

size_t
objectsCount() const;


status_t
errorCheck() const;

void
setError(status_t err);


status_t
write(const void* data, size_t len);

void*
writeInplace(size_t len);

status_t
writeUnpadded(const void* data, size_t len);

status_t
writeInt32(int32_t val);

status_t
writeInt64(int64_t val);

status_t
writeFloat(float val);

status_t
writeDouble(double val);

status_t
writeIntPtr(intptr_t val);

status_t
writeCString(const char* str);

status_t
writeString8(const String8& str);

status_t
writeString16(const String16& str);

status_t
writeString16(const char16_t* str, size_t len);

status_t
writeStrongBinder(const sp<IBinder>& val);

status_t
writeWeakBinder(const wp<IBinder>& val);

status_t
write(const Flattenable& val);


// Place a native_handle into the parcel (the native_handle's file-

// descriptors are dup'ed, so it is safe to delete the native_handle

// when this function returns). 

// Doesn't take ownership of the native_handle.

status_t
writeNativeHandle(const native_handle* handle);


// Place a file descriptor into the parcel.
The given fd must remain

// valid for the lifetime of the parcel.

status_t
writeFileDescriptor(int fd);


// Place a file descriptor into the parcel.
A dup of the fd is made, which

// will be closed once the parcel is destroyed.

status_t
writeDupFileDescriptor(int fd);


status_t
writeObject(const flat_binder_object& val, bool nullMetaData);


void
remove(size_t start, size_t amt);


status_t
read(void* outData, size_t len) const;

const void*
readInplace(size_t len) const;

int32_t
readInt32() const;

status_t
readInt32(int32_t *pArg) const;

int64_t
readInt64() const;

status_t
readInt64(int64_t *pArg) const;

float
readFloat() const;

status_t
readFloat(float *pArg) const;

double
readDouble() const;

status_t
readDouble(double *pArg) const;

intptr_t
readIntPtr() const;

status_t
readIntPtr(intptr_t *pArg) const;


const char*
readCString() const;

String8
readString8() const;

String16
readString16() const;

const char16_t*
readString16Inplace(size_t* outLen) const;

sp<IBinder>
readStrongBinder() const;

wp<IBinder>
readWeakBinder() const;

status_t
read(Flattenable& val) const;


// Retrieve native_handle from the parcel. This returns a copy of the

// parcel's native_handle (the caller takes ownership). The caller

// must free the native_handle with native_handle_close() and 

// native_handle_delete().

native_handle*
readNativeHandle() const;



// Retrieve a file descriptor from the parcel.
This returns the raw fd

// in the parcel, which you do not own -- use dup() to get your own copy.

int
readFileDescriptor() const;


const flat_binder_object* readObject(bool nullMetaData) const;


// Explicitly close all file descriptors in the parcel.

void
closeFileDescriptors();


typedef void
(*release_func)(Parcel* parcel,

const uint8_t* data, size_t dataSize,

const size_t* objects, size_t objectsSize,

void* cookie);


const uint8_t*
ipcData() const;

size_t
ipcDataSize() const;

const size_t*
ipcObjects() const;

size_t
ipcObjectsCount() const;

void
ipcSetDataReference(const uint8_t* data, size_t dataSize,

const size_t* objects, size_t objectsCount,

release_func relFunc, void* relCookie);


void
print(TextOutput& to, uint32_t flags = 0) const;

private:

Parcel(const Parcel& o);

Parcel&
operator=(const Parcel& o);


status_t
finishWrite(size_t len);

void
releaseObjects();

void
acquireObjects();

status_t
growData(size_t len);

status_t
restartWrite(size_t desired);

status_t
continueWrite(size_t desired);

void
freeDataNoInit();

void
initState();

void
scanForFds() const;


template<class T>

status_t
readAligned(T *pArg) const;


template<class T>
T readAligned() const;


template<class T>

status_t
writeAligned(T val);


status_t
mError;

uint8_t*
mData;

size_t
mDataSize;

size_t
mDataCapacity;

mutable size_t
mDataPos;

size_t*
mObjects;

size_t
mObjectsSize;

size_t
mObjectsCapacity;

mutable size_t
mNextObjectHint;


mutable bool
mFdsKnown;

mutable bool
mHasFds;


release_func
mOwner;

void*
mOwnerCookie;
};

虽然public方法有很多,但是我们先只要注意它的成员变量即可,特别是mData,mDataSize,mDataCapacity,mDataPos,mObjects,mObjectsSize,mObjectsCapacity这几个成员变量。

另外,为了方便大家理解,先说1个结论:对于普通数据,使用mData进行储存;对于IBinder类型的数据以及FileDescriptor使用的是mObjects;

1.Parcel类的初始化

在C++中,类的初始化非常重要,可能在成员初始化列表中就进行非常多的操作。所以首先要看它的构造函数:

1
2
3
4
Parcel::Parcel()
{

initState();
}

出乎意料地是,Parcel类的构造方法异常简单,就是调用initState()方法,下面是initState()的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void Parcel::initState()
{

mError = NO_ERROR;

mData = 0;

mDataSize = 0;

mDataCapacity = 0;

mDataPos = 0;

LOGV("initState Setting data size of %p to %dn", this, mDataSize);

LOGV("initState Setting data pos of %p to %dn", this, mDataPos);

mObjects = NULL;

mObjectsSize = 0;

mObjectsCapacity = 0;

mNextObjectHint = 0;

mHasFds = false;

mFdsKnown = true;

mOwner = NULL;
}

可以发现,initState()函数主要就是对成员变量初始化。而mDataSize,mDataCapacity,mDataPos,mObjectsSize,mObjectsCapacity都为0,另外指针都初始化为NULL.注意这些成员的初始值很重要,因为后面会用到。

2.finish_flatten_binder()

由于在上一篇Blog中已经分析过Parcel::writeStrongBinder()和flatten_binder()函数,所以这里直接分析finish_flatten_binder()方法了。该方法的代码如下:

1
2
3
4
inline static status_t finish_flatten_binder(const sp<IBinder>& binder,const flat_binder_object& flat,Parcel* out)
{

return out->writeObject(flat,false);
}

竟然又是调用,这个嵌套太多了,而且binder参数没有再被用到的话,其实就可以不传递过来了。下面看Parcel::writeObject()方法的代码:

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
status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
{

const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;

const bool enoughObjects = mObjectsSize < mObjectsCapacity;

if (enoughData && enoughObjects) {
restart_write:

//code_1

*reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;


// Need to write meta-data?

//code_2

if (nullMetaData || val.binder != NULL) {

mObjects[mObjectsSize] = mDataPos;

acquire_object(ProcessState::self(), val, this);

mObjectsSize++;

}


// remember if it's a file descriptor

//code_3

if (val.type == BINDER_TYPE_FD) {

mHasFds = mFdsKnown = true;

}

//code_4

return finishWrite(sizeof(flat_binder_object));

}


//code_5

if (!enoughData) {

const status_t err = growData(sizeof(val));

if (err != NO_ERROR) return err;

}

//code_6

if (!enoughObjects) {

size_t newSize = ((mObjectsSize+2)*3)/2;

size_t* objects = (size_t*)realloc(mObjects, newSize*sizeof(size_t));

if (objects == NULL) return NO_MEMORY;

mObjects = objects;

mObjectsCapacity = newSize;

}


goto restart_write;
}

由于从Parcel data;定义之后,一直到这里,除了写入接口描述符和服务名称之外,并没有改变data的其他成员变量,所以mDataPos,mDataCapacity,mObjectsSize,mObjectsCapacity仍然是初始值0,所以enoughData,enoughObjects均为false.

所以先执行code_5和code_6处的代码,先看growData()方法的代码:

1
2
3
4
5
6
7
status_t Parcel::growData(size_t len)
{

size_t newSize=((mDataSize+len)*3)/2;

return (newSize<=mDataSize)

? (status_t) NO_MEMORY

: continueWrite(newSize);
}

其中len是flat_binder_object的大小,显然这里无论如何都不会出现newSize<=mDataSize的情况,所以这里是个很明显的bug,存在着内存泄露的风险。 下面我们看一下continueWrite(newSize)的代码,注意此时传入的参数值是(mDataSize+len)*3/2:

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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
status_t Parcel::continueWrite(size_t desired)
{

// If shrinking, first adjust for any objects that appear

// after the new data size.

size_t objectsSize = mObjectsSize;

//code_1

if (desired < mDataSize) {

if (desired == 0) {

objectsSize = 0;

} else {

while (objectsSize > 0) {

if (mObjects[objectsSize-1] < desired)

break;

objectsSize--;

}

}

}

//code_2

if (mOwner) {

// If the size is going to zero, just release the owner's data.

if (desired == 0) {

freeData();

return NO_ERROR;

}


// If there is a different owner, we need to take

// posession.

uint8_t* data = (uint8_t*)malloc(desired);

if (!data) {

mError = NO_MEMORY;

return NO_MEMORY;

}

size_t* objects = NULL;


if (objectsSize) {

objects = (size_t*)malloc(objectsSize*sizeof(size_t));

if (!objects) {

mError = NO_MEMORY;

return NO_MEMORY;

}


// Little hack to only acquire references on objects

// we will be keeping.

size_t oldObjectsSize = mObjectsSize;

mObjectsSize = objectsSize;

acquireObjects();

mObjectsSize = oldObjectsSize;

}


if (mData) {

memcpy(data, mData, mDataSize < desired ? mDataSize : desired);

}

if (objects && mObjects) {

memcpy(objects, mObjects, objectsSize*sizeof(size_t));

}

//LOGI("Freeing data ref of %p (pid=%d)n", this, getpid());

mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);

mOwner = NULL;


mData = data;

mObjects = objects;

mDataSize = (mDataSize < desired) ? mDataSize : desired;

LOGV("continueWrite Setting data size of %p to %dn", this, mDataSize);

mDataCapacity = desired;

mObjectsSize = mObjectsCapacity = objectsSize;

mNextObjectHint = 0;


} else if (mData) {
//code_3

if (objectsSize < mObjectsSize) {

// Need to release refs on any objects we are dropping.

const sp<ProcessState> proc(ProcessState::self());

for (size_t i=objectsSize; i<mObjectsSize; i++) {

const flat_binder_object* flat

= reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);

if (flat->type == BINDER_TYPE_FD) {

// will need to rescan because we may have lopped off the only FDs

mFdsKnown = false;

}

release_object(proc, *flat, this);

}

size_t* objects =

(size_t*)realloc(mObjects, objectsSize*sizeof(size_t));

if (objects) {

mObjects = objects;

}

mObjectsSize = objectsSize;

mNextObjectHint = 0;

}


// We own the data, so we can just do a realloc().

if (desired > mDataCapacity) {

uint8_t* data = (uint8_t*)realloc(mData, desired);

if (data) {

mData = data;

mDataCapacity = desired;

} else if (desired > mDataCapacity) {

mError = NO_MEMORY;

return NO_MEMORY;

}

} else {

mDataSize = desired;

LOGV("continueWrite Setting data size of %p to %dn", this, mDataSize);

if (mDataPos > desired) {

mDataPos = desired;

LOGV("continueWrite Setting data pos of %p to %dn", this, mDataPos);

}

}


} else {
//code_4

// This is the first data.
Easy!

uint8_t* data = (uint8_t*)malloc(desired);

if (!data) {

mError = NO_MEMORY;

return NO_MEMORY;

}


if(!(mDataCapacity == 0 && mObjects == NULL

&& mObjectsCapacity == 0)) {

LOGE("continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired);

}


mData = data;

mDataSize = mDataPos = 0;

LOGV("continueWrite Setting data size of %p to %dn", this, mDataSize);

LOGV("continueWrite Setting data pos of %p to %dn", this, mDataPos);

mDataCapacity = desired;

}


return NO_ERROR;
}

其实这个方法写得挺糟糕的,有那么多分支,应该增加几个工具函数,这样一个函数的代码量就不会那么大了,阅读代码就会方便很多。
由于传入的desired值为(mDataSize+size(val))*3/2,肯定大于mDataSize,再加上mOwner和mData仍然为NULL,所以这里不会执行code_1,code_2和code_3这3部分代码。只需要看code_4这个分支下的代码。

这段代码非常简单,就是先调用malloc()方法分配一块(mDataSize+size(val))*3/2大小的内存,然后让mData指向该内存,并且将mDataCapacity的值修改为分配内存的大小。

到这里可以归纳一下,growData()方法只是分配了一块比flat_binder_object对象大一些的内存,但是暂时还没有将数据放进去。


再回到Parcela::writeObject()方法中,下面执行的仍然是从堆上分配内存,分配好之后让mObjects指向内存的起始位置,并且mObjectsCapacity赋值为刚刚分配的内存大小。另外,由于mObjectsSize初始值为0,所以这里其实newSize==3,从而分配的内存大小其实是3*sizeof(size_t);其中size_t是typedef unsigned long size_t,所以sizeof(size_t)的结果为4,从而这里最终是分配了12个字节的内存大小。

接着是goto restart_write,再次吐槽一句,Android Framework的架构虽然很好,但是有些代码质量堪忧,像这样的goto语句在很多个地方出现过。还有像interpret_cast这样很容易导致程序crash的转化其实也应该尽量避免的。

reinterpret_cast<flat_binder_object>(mData+mDataPos)=val;的作用是将从mData+mDataPos位置处开始的内存内容填充为flat_binder_object对象val的值;

虽然nullMetaData为false,但是val.binder不为NULL,所以下面会给mObjects数组赋值,此时mObjectsSize==0,所以mObjects数组中第一个元素为mDataPos,下面进入acquire_object()方法:

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
void acquire_object(const sp<ProcessState>& proc,
const flat_binder_object& obj, const void* who)
{

switch (obj.type) {

case BINDER_TYPE_BINDER:

if (obj.binder) {

LOG_REFS("Parcel %p acquiring reference on local %p", who, obj.cookie);

static_cast<IBinder*>(obj.cookie)->incStrong(who);

}

return;

case BINDER_TYPE_WEAK_BINDER:

if (obj.binder)

static_cast<RefBase::weakref_type*>(obj.binder)->incWeak(who);

return;

case BINDER_TYPE_HANDLE: {

const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);

if (b != NULL) {

LOG_REFS("Parcel %p acquiring reference on remote %p", who, b.get());

b->incStrong(who);

}

return;

}

case BINDER_TYPE_WEAK_HANDLE: {

const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);

if (b != NULL) b.get_refs()->incWeak(who);

return;

}

case BINDER_TYPE_FD: {

// intentionally blank -- nothing to do to acquire this, but we do

// recognize it as a legitimate object type.

return;

}

}


LOGD("Invalid object type 0x%08lx", obj.type);
}

注意到传入的参数分别是:ProcessState::self(),flat_binder_object对象以及Parcel对象,由于obj.type为BINDER_TYPE_BINDER,所以obj的cookie对象,其实就是之前创建的MediaPlayerService对象执行incStrong()函数,这里涉及到指针的引用问题,后面会有专门的博客进行深入讲解,这里可以将其简单地理解成为Parcel对象增加一次引用。

之后再回到Parcel::writeObject()方法中,mObjectsSize执行自加操作之后变为1.


由于val.type值是BINDER_TYPE_BINDER,所以下面进入到Parcel::finishWrite()方法中,注意传入的参数sizeof(flat_binder_object)值为16:

1
2
3
4
5
6
7
8
9
10
11
12
status_t Parcel::finishWrite(size_t len)
{

//printf("Finish write of %dn", len);

mDataPos += len;

LOGV("finishWrite Setting data pos of %p to %dn", this, mDataPos);

if (mDataPos > mDataSize) {

mDataSize = mDataPos;

LOGV("finishWrite Setting data size of %p to %dn", this, mDataSize);

}

//printf("New pos=%d, size=%dn", mDataPos, mDataSize);

return NO_ERROR;
}

这个方法异常简单,就是让mDataPos增加到刚刚写入数据的末尾,并且进行一个判断,如果mDataPos>mDataSize的话,就将mDataSize=mDataPos;而实际上mDataSize在赋值前还是0,所以会进行这个赋值操作,因此我们可以知道,其实mDataSize是记录当前mData中写入数据的大小。

到这里,我们就将flat_binder_object这个对象写入到Parcel对象中的mData指向的内存中。

最后,欢迎大家关注我的微信公众号:AndroidGeek.  AndroidGeek专注于Android源码解析、框架设计、最新技术分享以及职位招聘和内推

最后

以上就是现代大山为你收集整理的Android Binder机制分析(4) Parcel类分析的全部内容,希望文章能够帮你解决Android Binder机制分析(4) Parcel类分析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(50)

评论列表共有 0 条评论

立即
投稿
返回
顶部