Binder 학습을 통해 Service Manager 객체 가져오기
int main(int argc, char** argv)
{
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
LOGI("ServiceManager: %p", sm.get());
waitBeforeAdding( String16("media.audio_flinger") );
AudioFlinger::instantiate();
waitBeforeAdding( String16("media.player") );
MediaPlayerService::instantiate();
waitBeforeAdding( String16("media.camera") );
CameraService::instantiate();
waitBeforeAdding( String16("media.audio_policy") );
AudioPolicyService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
첫 마디부터 시작해 봅시다. sp
ProcessState::self()를 다시 한 번 살펴보자. 함수 이름을 통해 모두가 하나의 단일 모드임을 알 수 있다.self로 프로세스 내의 전체 대상을 만들고 코드를 보자.
sp<ProcessState> ProcessState::self()
{
if (gProcess != NULL) return gProcess;
AutoMutex _l(gProcessMutex);
if (gProcess == NULL) gProcess = new ProcessState;
return gProcess;
}
그렇지!결과적으로 ProcessState 객체가 반환됩니다.
그럼 AutoMutex는 어디에서 신성한가요? 여기서 우리는 코드를 보지 않고 너무 멀리 가지 않도록 하겠습니다. 제가 직접 여러분께 말씀드리자면 하나의 라인이 동기화되는 메커니즘입니다.
관련 실현 코드:frameworks/base/include/utils/threads.h, 관심 있는 신발동은 볼 수 있어요.
자, 이제 ProcessState의 구조 함수를 살펴보겠습니다. 또 무엇을 했을까요?
ProcessState::ProcessState()
: mDriverFD(open_driver())
, mVMStart(MAP_FAILED)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
{
if (mDriverFD >= 0) {
// XXX Ideally, there should be a specific define for whether we
// have mmap (or whether we could possibly have the kernel module
// availabla).
#if !defined(HAVE_WIN32_IPC)
// mmap the binder, providing a chunk of virtual address space to receive transactions.
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
// *sigh*
LOGE("Using /dev/binder failed: unable to mmap transaction memory.
");
close(mDriverFD);
mDriverFD = -1;
}
#else
mDriverFD = -1;
#endif
}
LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
}
첫 번째 문장은 Binder의 핵심인 것 open 입니다.driver().
static int open_driver()
{
int fd = open("/dev/binder", O_RDWR);
if (fd >= 0) {
fcntl(fd, F_SETFD, FD_CLOEXEC);
int vers;
status_t result = ioctl(fd, BINDER_VERSION, &vers);
if (result == -1) {
LOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
close(fd);
fd = -1;
}
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
LOGE("Binder driver protocol does not match user space protocol!");
close(fd);
fd = -1;
}
size_t maxThreads = 15;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -1) {
LOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
} else {
LOGW("Opening '/dev/binder' failed: %s
", strerror(errno));
}
return fd;
}
이곳에는 두 가지 중요한 개념이 있는데 첫 번째는 Binder 드라이브를 켜서 FD를 얻는 것이고 두 번째는 Binder 프로세스가 지원하는 라인의 최대 값을 가리킨다.
자, Process State의 구조 함수로 돌아가면 일부 구성원 변수를 초기화하는 것 이외에 Binder에 가상 메모리를 설정하는 것을 볼 수 있다. 이 메모리를 구분하는 목적은 클라이언트와 서버가 통신할 때의 데이터 저장에 있다.
이어서 Main 을 보도록 하겠습니다.MediaServer main 함수의 두 번째 문장인 sp
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
if (gDefaultServiceManager == NULL) {
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
}
}
return gDefaultServiceManager;
}
여기는 또 하나의 예입니다. 먼저 Process State::self()->get Context Object(NULL)가 무엇입니까?
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
{
return getStrongProxyForHandle(0);
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
// We need to create a new BpBinder if there isn't currently one, OR we
// are unable to acquire a weak reference on this current one. See comment
// in getWeakProxyForHandle() for more info about this.
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
// This little bit of nastyness is to allow us to add a primary
// reference to the remote proxy when this team doesn't have one
// but another team is sending the handle to us.
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
const size_t N=mHandleToObject.size();
if (N <= (size_t)handle) {
handle_entry e;
e.binder = NULL;
e.refs = NULL;
status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
if (err < NO_ERROR) return NULL;
}
return &mHandleToObject.editItemAt(handle);
}
위의 코드에서 getContextObject(NULL)가handle==0의 BpBinder를 되돌려받았다는 것을 알 수 있습니다.
사실 여기서 우리는 Binder와 통신하는 Binder 대상인 BpBinder를 끌어냈다. 이것은 클라이언트의 Binder 에이전트이다. 클라이언트가 Binder와 통신하려면 반드시 그것을 빌려야 한다. 그러면 클라이언트와 대응하는 서비스 측에도 Binder와 통신하는 구성 요소가 있겠지?서두르지 말고 문제를 가지고 계속 가자.
그럼 인터페이스 한번 더 볼까요?cast
IIterface에 정의됩니다.h,IServiceManager.cpp가 IIterface에 어떻게 인용되는지 다른 문장을 매개 변수로 설정할 수 있습니다.
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}
우리는 IService Manager가 들어갔다가 다시 돌아왔기 때문에 IService Manager에서 asInterface라는 방법을 찾아야 하는데 결국 찾지 못했다.
사실 MFC 같은 거 하나 소홀히 하셨잖아요.
IServiceManager에서.h에서는 다음과 같은 매크로 함수를 참조합니다.
DECLARE_META_INTERFACE(ServiceManager);
#define DECLARE_META_INTERFACE(INTERFACE) \
static const android::String16 descriptor; \
static android::sp<I##INTERFACE> asInterface( \
const android::sp<android::IBinder>& obj); \
virtual const android::String16& getInterfaceDescriptor() const; \
I##INTERFACE(); \
virtual ~I##INTERFACE();
이 정의는 asInterface에서 Ibinder의 바늘 대상의 주소를 받을 수 있습니다. 만약에 위의 코드를 되돌려준다면, 우리가 이전에 전송한 매개 변수는 BpBinder이고, BpBinder는 Ibinder를 계승하고, 되돌려준 것은 IService Manager입니다.이어서 이 asInterface의 실현을 살펴봅시다!
IServiceManager.cpp에서도 IIterface가 호출되었습니다.h의 매크로 정의:
IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
const android::String16 I##INTERFACE::descriptor(NAME); \
const android::String16& \
I##INTERFACE::getInterfaceDescriptor() const { \
return I##INTERFACE::descriptor; \
} \
android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
const android::sp<android::IBinder>& obj) \
{ \
android::sp<I##INTERFACE> intr; \
if (obj != NULL) { \
intr = static_cast<I##INTERFACE*>( \
obj->queryLocalInterface( \
I##INTERFACE::descriptor).get()); \
if (intr == NULL) { \
intr = new Bp##INTERFACE(obj); \
} \
} \
return intr; \
} \
I##INTERFACE::I##INTERFACE() { } \
I##INTERFACE::~I##INTERFACE() { }
Interface가 되돌아오는 것이 바로 BpService Manager이기 때문에 앞의default Service Manager가 얻은 것이 바로 이 대상입니다. 그래서 우리는 그것이 무엇인지 다시 찾아보겠습니다.
class BpServiceManager : public BpInterface<IServiceManager>
{
public:
BpServiceManager(const sp<IBinder>& impl)
: BpInterface<IServiceManager>(impl)
{
}
virtual sp<IBinder> getService(const String16& name) const
{
unsigned n;
for (n = 0; n < 5; n++){
sp<IBinder> svc = checkService(name);
if (svc != NULL) return svc;
LOGI("Waiting for service %s...
", String8(name).string());
sleep(1);
}
return NULL;
}
virtual sp<IBinder> checkService( const String16& name) const
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
return reply.readStrongBinder();
}
virtual status_t addService(const String16& name, const sp<IBinder>& service)
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
virtual Vector<String16> listServices()
{
Vector<String16> res;
int n = 0;
for (;;) {
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeInt32(n++);
status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);
if (err != NO_ERROR)
break;
res.add(reply.readString16());
}
return res;
}
};
BpService Manager의 구조 함수에서 BpInterface
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.