This article was published on the public account: Android supply website, focusing on Android progression, algorithm and interview analysis.
In the Binder: ServiceManager acquisition article, the ProcessState and IPCThreadState creation are analyzed. Finally, in defaultServiceManager, the BpServiceManager object holding BpBinder is returned.
int main(int argc __unused, char **argv __unused)
{
signal(SIGPIPE, SIG_IGN);
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm(defaultServiceManager()); // BpServiceManager
ALOGI("ServiceManager: %p", sm.get());
AIcu_initializeIcuOrDie();
MediaPlayerService::instantiate();
ResourceManagerService::instantiate();
registerExtensions();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
}
Copy the code
So the addService called in the Instantiate method is actually the BpServiceManager method that registers the MediaPlayerService object named Media.Player
addService
Let’s look directly at addService in BpServiceManager.
virtual status_t addService(const String16& name, const sp<IBinder>& service, bool allowIsolated, Int dumpsysPriority) {// Encapsulate to Parcel object Parcel data, reply; data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); data.writeString16(name); data.writeStrongBinder(service); data.writeInt32(allowIsolated ? 1:0); data.writeInt32(dumpsysPriority); Status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); return err == NO_ERROR ? reply.readExceptionCode() : err; }Copy the code
The data is encapsulated into a Parcel object and finally transferred to the remote using remote() ‘s transact method with the code ADD_SERVICE_TRANSACTION.
Now let’s take a look at what remote() really is.
It is a method in BpServiceManager that comes from its parent class
class BpServiceManager : public BpInterface<IServiceManager>
public:
explicit BpServiceManager(const sp<IBinder>& impl) // BpBinder(0)
: BpInterface<IServiceManager>(impl) {}
inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote) : BpRefBase(remote)
BpRefBase::BpRefBase(const sp<IBinder>& o) : mRemote(o.get()), mRefs(nullptr), mState(0)
class BpRefBase : public virtual RefBase
{
protected:
explicit BpRefBase(const sp<IBinder>& o);
virtual ~BpRefBase();
virtual void onFirstRef();
virtual void onLastStrongRef(const void* id);
virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
inline IBinder* remote() { return mRemote; }
inline IBinder* remote() const { return mRemote; }
private:
BpRefBase(const BpRefBase& o);
BpRefBase& operator=(const BpRefBase& o);
IBinder* const mRemote;
RefBase::weakref_type* mRefs;
std::atomic<int32_t> mState;
};
Copy the code
Inheriting from the process above, the remote() returns mRemote, which is the original parameter BpBinder(0). The transact method of BpBinder is called
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
Copy the code
Enter BpBinder and find transact methods that switch to IPCThreadState
status_t IPCThreadState::transact(int32_t handle, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { ... Err = writeTransactionData(BC_TRANSACTION, FLAGS, Handle, code, data, nullptr); if ((flags & TF_ONE_WAY) == 0) { ... If (reply) {err = waitForResponse(reply); } else { Parcel fakeReply; err = waitForResponse(&fakeReply); } } else { err = waitForResponse(nullptr, nullptr); } return err; }Copy the code
There are two main things to do here
- through
writeTransactionData
Write data toParcel
, corresponding tocmd
Command toBC_TRANSACTION
, this is the request code, the corresponding isBC_
Name it at the beginningservice
The end will use these request codes to do different logic processing. - through
waitForResponse
To wait for the data to return from the remote side, and there’s one here as wellcmd
Command line, for exampleBR_REPLY
, this is the return code, the corresponding isBR_
It’s named at the beginning, inclient
It also uses these return codes to do different logic processing.
We won’t look at these methods today; future articles will focus on data interaction.
Now that MediaPlayerService is registered, let’s take the main method and go down.
startThreadPool
ProcessState::self()->startThreadPool();
Copy the code
Again, the method in ProcessState, go to startThreadPooll and see.
void ProcessState::startThreadPool() { AutoMutex _l(mLock); if (! mThreadPoolStarted) { mThreadPoolStarted = true; spawnPooledThread(true); } } void ProcessState::spawnPooledThread(bool isMain) { if (mThreadPoolStarted) { String8 name = makeBinderThreadName(); Sp <Thread> t = new PoolThread(isMain); t->run(name.string()); }}Copy the code
The PoolThread pool is created in the spawnPooledThread method, which inherits from Thread and finally calls the run method of the Thread
joinThreadPool
IPCThreadState::self()->joinThreadPool();
Copy the code
Moving on to the joinThreadPooll method, which is in IPCThreadState
void IPCThreadState::joinThreadPool(bool isMain) { mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); status_t result; do { processPendingDerefs(); // Waiting for the command line result = getAndExecuteCommand(); } while (result ! = -ECONNREFUSED && result ! = -EBADF); mOut.writeInt32(BC_EXIT_LOOPER); // Communicate with binder driver talkWithDriver(false); }Copy the code
The main method here is getAndExecuteCommand(), which is used to process data from the receiving service, since the service and client can initiate data interaction with each other. In this case, the client acts as a service. It starts polling and listens for the data sent by the service. Eventually it calls executeCommand to unify the processing.
status_t IPCThreadState::executeCommand(int32_t cmd) { switch ((uint32_t)cmd) { ... case BR_TRANSACTION_SEC_CTX: case BR_TRANSACTION: { ... if (tr.target.ptr) { if (reinterpret_cast<RefBase::weakref_type*>( tr.target.ptr)->attemptIncStrong(this)) { // BBinder 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); }... If ((tr.flags & TF_ONE_WAY) == 0) {// Send a reply to the server. sendReply(reply, 0); } else { LOG_ONEWAY("NOT sending reply to %d!" , mCallingPid); }... } break; . default: ALOGE("*** BAD COMMAND %d received from Binder driver\n", cmd); result = UNKNOWN_ERROR; break; } if (result ! = NO_ERROR) { mLastError = result; } return result; }Copy the code
To simplify the code and show only the main parts of the code, BR_TRANSACTION is similar to BC_TRANSACTION, where data is sent from the server, indicating that the server actively transfers data.
Therefore, the communication with the server is established.
So far, the data interaction process on the client side has been analyzed. Subsequently, we will look at the service side in the transmission process of binder to see how it receives and processes data.
recommended
Android_startup: Provides a simpler and more efficient way to initialize components at application startup. Developers can use Android-startup to simplify the startup sequence and explicitly set the dependency between the initialization order and the components. Meanwhile, Android-startup supports synchronous and asynchronous wait, and ensures the initialization sequence of internal dependent components by means of directed acyclic topology sorting.
AwesomeGithub: Based on Github client, pure exercise project, support componentized development, support account password and authentication login. Kotlin language for development, the project architecture is based on Jetpack&DataBinding MVVM; Popular open source technologies such as Arouter, Retrofit, Coroutine, Glide, Dagger and Hilt are used in the project.
Flutter_github: a cross-platform Github client based on Flutter, corresponding to AwesomeGithub.
Android-api-analysis: A comprehensive analysis of Knowledge points related to Android with detailed Demo to help readers quickly grasp and understand the main points explained.
Daily_algorithm: advanced algorithm, from shallow to deep, welcome to join us.