Upload
lb
View
96
Download
4
Embed Size (px)
Citation preview
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
ReceiverApplication
SenderApplication
Binderの仕組み
● Binder Driver(/dev/binder)にアクセスしているのはフレームワーク中、ServiceManager(ソースの/framework/base/cmds/servicemanager/service_manager.c)とlibBinder(/framework/base/libs/binder/ProcessState.cpp)のみ。○この中の仕組みはまだ追えていません。
●ユーザーアプリケーションは直接Binderドライバを操作することはない。
Binderの仕組み
● Binderを受信するアプリはServiceManagerに自身をサービスとして登録する。(図の水色矢印)
●受信するアプリはBBinderを継承し、onTransact()で受信処理を実装。
● Binderを送信するアプリはServiceManagerから送信先サービスを取得し(図の緑矢印)、取得したIBinderサービスに対しtransact()でメッセージを送信(図の赤矢印)。
実際に使ってみる
Binderを受信するNativeデーモン(BinderReceiver)と、送信する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=%d\n",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 %p\n",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/bashANDROID_ROOT=~/android/myfroyosource $ANDROID_ROOT/build/envsetup.shcd ~/android/myfroyo/external/binder_samplemm
●全体のAndroid.mk
include $(all-subdir-makefiles)
実行結果のログ
D/RECEIVER( 286): Reciever start.D/RECEIVER( 286): ServiceManager: 0xb678D/RECEIVER( 286): Receiver created.D/SENDER ( 288): Sender getService 0xa678D/SENDER ( 288): pid=288D/SENDER ( 288): num=12D/RECEIVER( 286): Message received code=0.D/RECEIVER( 286): Sender pid=288D/RECEIVER( 286): Number Data=12D/SENDER ( 288): reply num=60
次回予告
Binder、ashmem、MemoryMappedFileなど各種IPCの使い方と、使った時の性能測定を考えています。(多分)