- Start the rc script file
//frameworks\av\camera\cameraserver\cameraserver.rc
service cameraserver /system/bin/cameraserver
- Process entry:
//frameworks\av\camera\cameraserver\main_cameraserver.cpp
int main(int argc __unused, char** argv __unused)
{
signal(SIGPIPE, SIG_IGN);
//之前讲过,会打开/dev/hwbinder,通知kernel,当前进程最大允许的binder线程池为maxThreads
// Set 3 threads for HIDL calls
hardware::configureRpcThreadpool(3, /*willjoin*/ false);
//创建ProcessState单例对象
sp<ProcessState> proc(ProcessState::self());
//获取IServiceManager服务代理对象BpServiceManager
//代码在/frameworks/native/libs/binder/IServiceManager.cpp
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
//1、创建CameraService
//2、触发CameraService::onFirstRef()
//3、将CameraService注册给IServiceManager
CameraService::instantiate();
//创建一个子线程并加入binder线程池
ProcessState::self()->startThreadPool();
//将主线程加入binder线程池
IPCThreadState::self()->joinThreadPool();
}
The CameraService::instantiate() method is introduced in detail below.
First, the class diagram of CameraService is given, as follows:
CameraService::instantiate() calls the method of its parent class BinderService
// /frameworks/native/include/binder/BinderService.h
static void instantiate() {
publish(); }
Then the publish() method is called
// /frameworks/native/include/binder/BinderService.h
static status_t publish(bool allowIsolated = false) {
//获取IServiceManager服务代理对象BpServiceManager
sp<IServiceManager> sm(defaultServiceManager());
//注册服务SERVICE为CameraService
return sm->addService(
String16(SERVICE::getServiceName()),
new SERVICE(), allowIsolated);
}
When registering a service, first call the CameraService::getServiceName()
acquired CameraService
service name- "media.camera"
and then create a new CameraService object.
The addService method of BpServiceManager is introduced below.
//frameworks\native\libs\binder\IServiceManager.cpp
virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated)
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
data.writeInt32(allowIsolated ? 1 : 0);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
It is found that the second parameter of addService is const sp& service. And the incoming CameraService object. Therefore, the automatic type conversion constructor of sp (Android smart pointer, not described in detail) will be called
//system\core\libutils\include\utils\StrongPointer.h
//T为IBinder;U为CameraService
template<typename T> template<typename U>
sp<T>::sp(U* other)
: m_ptr(other) {
//类型转换后调用incStrong方法
if (other)
(static_cast<T*>(other))->incStrong(this);
}
incStrong will trigger the onFirstRef method, the code is as follows
//system/core/libutils/RefBase.cpp
void RefBase::incStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
refs->incWeak(id);
refs->addStrongRef(id);
const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
if (c != INITIAL_STRONG_VALUE) {
return;
}
int32_t old = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
std::memory_order_relaxed);
//触发onFirstRef方法
refs->mBase->onFirstRef();
}
Then CameraService::onFirstRef() will be triggered
void CameraService::onFirstRef()
{
ALOGI("CameraService process starting");
BnCameraService::onFirstRef();
...
//在以前的文章中介绍过,不做详细介绍了
res = enumerateProviders();
...
CameraService::pingCameraServiceProxy();
}
The function of enumerateProviders() is described in
detail in the CameraService startup process-the process of obtaining the ICameraProvider service proxy object BpHwCameraProvider and thereby obtaining all camera device proxy objects BpHwCameraDevice . I will not introduce it in detail here.
So far, the analysis of the CameraService::instantiate() process has
been completed. Summary: The three tasks completed by CameraService::instantiate() are listed in order, including:
- New CameraService object
- Trigger the CameraService onFirstRef class method
- Register service to ServiceManager
Next, continue to analyze ProcessState::self()->startThreadPool(); The
code is as follows:
//frameworks\native\libs\binder\ProcessState.cpp
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
//创建一个新的线程
spawnPooledThread(true);
}
}
Then analyze spawnPooledThread, the code is as follows:
frameworks\native\libs\binder\ProcessState.cpp
//isMain为true,说明是主线程
void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
//创建线程的名字Binder:PID_%X
String8 name = makeBinderThreadName();
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
//创建一个新线程并启动
sp<Thread> t = new PoolThread(isMain);
t->run(name.string());
}
}
Then analyze the thread loop threadLoop
//frameworks\native\libs\binder\ProcessState.cpp
class PoolThread : public Thread
{
public:
explicit PoolThread(bool isMain)
: mIsMain(isMain)
{
}
protected:
//子线程循环
virtual bool threadLoop()
{
//子线程开启循环,不断读取/dev/binder以获取其他进程发来的命令并执行
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
const bool mIsMain;
};
Then it will call `IPCThreadState::self()->joinThreadPool(mIsMain)``, the code is as follows:
//frameworks\native\libs\binder\IPCThreadState.cpp
void IPCThreadState::joinThreadPool(bool isMain)
{
LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
//将当前线程加入到 binder线程池中。
//在上边的代码中可知,现在是将子线程加入到Binder线程池
//main为true
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
status_t result;
//开启循环,与dev/binder通讯,将mOut中的cmd写入binder驱动
do {
processPendingDerefs();
//获取命令并执行或者等待命令
// now get the next command to be processed, waiting if necessary
result = getAndExecuteCommand();
if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
mProcess->mDriverFD, result);
abort();
}
// Let this thread exit the thread pool if it is no longer
// needed and it is not the main process thread.
if(result == TIMED_OUT && !isMain) {
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);
LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%d\n",
(void*)pthread_self(), getpid(), result);
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}
Then analyze getAndExecuteCommand, the code is as follows:
//frameworks\native\libs\binder\IPCThreadState.cpp
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
//与/dev/binder通讯
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) return result;
//获取cmd
cmd = mIn.readInt32();
....
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount++;
if (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads &&
mProcess->mStarvationStartTimeMs == 0) {
mProcess->mStarvationStartTimeMs = uptimeMillis();
}
pthread_mutex_unlock(&mProcess->mThreadCountLock);
//执行命令
result = executeCommand(cmd);
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount--;
if (mProcess->mExecutingThreadsCount < mProcess->mMaxThreads &&
mProcess->mStarvationStartTimeMs != 0) {
int64_t starvationTimeMs = uptimeMillis() - mProcess->mStarvationStartTimeMs;
if (starvationTimeMs > 100) {
ALOGE("binder thread pool (%zu threads) starved for %" PRId64 " ms",
mProcess->mMaxThreads, starvationTimeMs);
}
mProcess->mStarvationStartTimeMs = 0;
}
pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
pthread_mutex_unlock(&mProcess->mThreadCountLock);
}
return result;
}
First explain executeCommand, the code is as follows:
//frameworks\native\libs\binder\IPCThreadState.cpp
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
...
//其他进程发来的消息
case BR_TRANSACTION:
{
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));
ALOG_ASSERT(result == NO_ERROR,
"Not enough command data for brTRANSACTION");
if (result != NO_ERROR) break;
Parcel buffer;
buffer.ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
const pid_t origPid = mCallingPid;
const uid_t origUid = mCallingUid;
const int32_t origStrictModePolicy = mStrictModePolicy;
const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;
mCallingPid = tr.sender_pid;
mCallingUid = tr.sender_euid;
mLastTransactionBinderFlags = tr.flags;
//ALOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
Parcel reply;
status_t error;
.....
if (tr.target.ptr) {
// We only have a weak reference on the target object, so we must first try to
// safely acquire a strong reference before doing anything else with it.
if (reinterpret_cast<RefBase::weakref_type*>(
tr.target.ptr)->attemptIncStrong(this)) {
//调用BnCameraService的 transact方法
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
&reply, tr.flags);
reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
} else {
error = UNKNOWN_TRANSACTION;
}
} else {
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
//ALOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
// mCallingPid, origPid, origUid);
if ((tr.flags & TF_ONE_WAY) == 0) {
LOG_ONEWAY("Sending reply to %d!", mCallingPid);
if (error < NO_ERROR) reply.setError(error);
sendReply(reply, 0);
} else {
LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
}
mCallingPid = origPid;
mCallingUid = origUid;
mStrictModePolicy = origStrictModePolicy;
mLastTransactionBinderFlags = origTransactionBinderFlags;
......
}
break;
....
default:
ALOGE("*** BAD COMMAND %d received from Binder driver\n", cmd);
result = UNKNOWN_ERROR;
break;
}
if (result != NO_ERROR) {
mLastError = result;
}
return result;
}
As for how to communicate with binder, I won’t introduce it in detail here, I will study it in the future.
So far, the analysis has completed the startup process of cameraserver. In
summary:
- Create CameraService object
- When CameraService is registered to ServiceManager, CameraService::onFirstRef is first triggered
- Register CameraService to ServiceManager
- Create a new binder thread pool and continuously read /dev/binder. If there is a message, it will call BBinder::transact and trigger the onTransact method of CameraService