Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
Binderのはじめの一歩    
Android IPCのとりあえず1回目
2010/09/19
@l_b__
横浜Androidプラットフォーム部
第2回勉強会でやらなかった
目次
●Binderって?
●何故Binder?
●Android独自のIPC
●Binderの歴史
●Binderの仕組み
●実際に使ってみる
●次回予告
Binderって?
●Android独自のプロセス間通信の一つ。
●POSIXメッセージの置き換え。
●プロセス間で小さいデータ(数百〜数千byte程度)を
高速にやり取りするために使用。
●何故POSIXのIPCがあるのにBinderという機構が導
入されたのか。
何故Binder
●AndroidはSystemV(UNIXの1種)のIPCをサポート
していない!
●NDKの/docs/system/libc/SYSV-IPC.TXTにサ
ポートされない理由の記述あり。
○カーネルでのリソースリークが発生する
○カーネルリソースを枯渇させるサンプルコードも有
り。(もちろんAndroidでは動かないのでLinuxで動
作させる必要あります。)
Android独自のIPC
●System V IPCの代わりは以下の通りと思われる。
○メッセージキューはBinderに。
○共有メモリはAnonymous Shared Memory
(ashmem)に。
○セマフォはPOSIX IPCのセマフォに。
Binderの歴史
● 元々はNext Generation BeOSに採用される予定だった
OpenBinder。(http://www.angryredplanet.
com/~hackbod/openbinder/)
● UNIXのCORBA、WindowsのCOMのように分散コンポーネント
環境を提供するフレームワーク。
● BeOSポシャっちゃったので残念ながら動くものとしては採用され
ず。
● OpenBinderをメンテしていたHackbornさんは今はAndroidのプ
ラットフォームエンジニア。よくGroupに投稿しています。
● 余談ですがBeの創業者Gasseeも、Danger、Androidの創業者
Andy Rubinも元Apple。Appleすごいですね。
Binderの仕組み
Kernel
Binder Driver
(/dev/binder)
ServiceManager libBinder
Receiver
Application
Sender
Application
Binderの仕組み
● Binder Driver(/dev/binder)にアクセスしているのはフレーム
ワーク中、ServiceManager(ソースの
/framework/base/cmds/servicemanager/service_manage
r.c)とlibBinder
(/framework/base/libs/binder/ProcessState.cpp)のみ。
○この中の仕組みはまだ追えていません。
● ユーザーアプリケーションは直接Binderドライバを操作することは
ない。
Binderの仕組み
● Binderを受信するアプリはServiceManagerに自身をサービスと
して登録する。(図の水色矢印)
● 受信するアプリはBBinderを継承し、onTransact()で受信処理を
実装。
● Binderを送信するアプリはServiceManagerから送信先サービス
を取得し(図の緑矢印)、取得したIBinderサービスに対し
transact()でメッセージを送信(図の赤矢印)。
実際に使ってみる
Binderを受信するNativeデーモン(Binder
Receiver)と、送信するNativeアプリ(BinderSender)を作ってみま
す。
実際に使ってみる 受信側
● main.cpp 受信側起動処理 SurfaceFlingerやAudioFlingerな
どが参考になります。
#define LOG_TAG "RECEIVER"
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include "receiver.h"
int main(int argc, char** argv) {
LOGD("Reciever start.");
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
LOGD("ServiceManager: %p", sm.get());
Receiver::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
実際に使ってみる 受信側
● receiver.h BBinderを継承した受信処理クラスの定義
#ifndef RECEIVER_H_
#define RECEIVER_H_
#include <utils/RefBase.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
using namespace android;
class Receiver:public BBinder {
public:
static void instantiate();
Receiver();
virtual ~Receiver();
virtual status_t onTransact(
uint32_t, const Parcel&, Parcel*, uint32_t);
};
#endif /* RECEIVER_H_ */
実際に使ってみる 受信側
● receiver.cpp Receiverクラスの実装。受けた数値を5倍して返
す。
#define LOG_TAG "RECEIVER"
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <utils/Log.h>
#include "receiver.h"
using namespace android;
void Receiver::instantiate() {
    defaultServiceManager()->addService(
            String16("Receiver"), new Receiver());
}
Receiver::Receiver() {
LOGD("Receiver created.n");
}
Receiver::~Receiver() {
LOGD("Receiver destroyed.n");
}
実際に使ってみる 受信側
● receiver.cpp 続き BBinder::onTransactの実装部分
status_t Receiver::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
LOGD("Message received code=%d.n", code);
pid_t pid;
int num;
switch(code) {
case 0:
pid = data.readInt32();
LOGD("Sender pid=%d", pid);
num = data.readInt32();
LOGD("Number Data=%dn",num);
reply->writeInt32(num*5);
break;
default:
//do nothing.
break;
}
return NO_ERROR;
}
実際に使ってみる 送信側
● receiver.cpp 送信処理。自プロセスIDと数値の12を送信する。
#define LOG_TAG "SENDER"
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <utils/RefBase.h>
#include <utils/Log.h>
using namespace android;
int main() {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("Receiver"));
LOGD("Sender getService %pn",sm.get());
if (binder == NULL) {
         LOGE("Receiver Service not found.n");
         return -1;
}
実際に使ってみる 送信側
● receiver.cpp 続き。実際の送信処理部分。
Parcel data, reply;
pid_t pid = getpid();
LOGD("pid=%d", pid);
data.writeInt32(pid);
int num = 12;
LOGD("num=%d", num);
data.writeInt32(num);
//非同期メッセージはFLAG_ONEWAYを4番目に追加
binder->transact(0, data, &reply);
LOGD("reply num=%d", reply.readInt32());
return NO_ERROR;
}
実際に使ってみる 受信側makefile
● receiver/Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= 
receiver.cpp 
main.cpp
LOCAL_SHARED_LIBRARIES:= 
libcutils 
libbinder
LOCAL_MODULE:= BinderReceiver
include $(BUILD_EXECUTABLE)
実際に使ってみる 送信側makefile
● sender/Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= 
sender.cpp
LOCAL_SHARED_LIBRARIES:= 
libcutils 
libbinder
LOCAL_MODULE:= BinderSender
include $(BUILD_EXECUTABLE)
実際に使ってみる ビルドスクリプト
● build/build.sh
#!/bin/bash
ANDROID_ROOT=~/android/myfroyo
source $ANDROID_ROOT/build/envsetup.sh
cd ~/android/myfroyo/external/binder_sample
mm
● 全体のAndroid.mk
include $(all-subdir-makefiles)
実行結果のログ
D/RECEIVER(  286): Reciever start.
D/RECEIVER(  286): ServiceManager: 0xb678
D/RECEIVER(  286): Receiver created.
D/SENDER  (  288): Sender getService 0xa678
D/SENDER  (  288): pid=288
D/SENDER  (  288): num=12
D/RECEIVER(  286): Message received code=0.
D/RECEIVER(  286): Sender pid=288
D/RECEIVER(  286): Number Data=12
D/SENDER  (  288): reply num=60
次回予告
Binder、ashmem、MemoryMappedFileなど各種IPCの使い方と、
使った時の性能測定を考えています。(多分)

More Related Content

Binderのはじめの一歩