Android Native layer Binder. transact () function call Binder. onTransact () function failure analysis

Source: Internet
Author: User

Android Native layer Binder. transact () function call Binder. onTransact () function failure analysis
Q: Why does the Android Native layer Binder. transact () function fail to call the Binder. onTransact () function?

Call Camera. when the api in h implements a screenshot function, it is found that gCamera-> setListener (new ScreenCaptureListener ()) the callback function set to the mListener of the Camera to receive the Preview Data of the Camera is not called, resulting in screen capture failure?

Note:
Summary of Camera files:
Libcamera_client.so
Camera
ICamera
ICameraClient
ICameraService
CameraBase
CameraHardwareInterface

Libcameraservice. so
CameraService
CameraClient
Camera2Client

A: Cause Analysis

The process for organizing the Camera preview should be as follows:

// TODO: Camera sets the call hierarchy from top to bottom. 1.
Native demo-> Camera-> CameraService-> CameraClient-> CameraHardwareInterface-> CameraHal_Module-> xcdiphardware_stein Stein-> PipManager
// TODO: callback call hierarchy of Camera from bottom up 2.
SN-> XCDipHardware_einstein-> CameraClient-> ICameraClient-> Camera-> SCREENSHOT_MAIN

Its LOG is as follows:

01-01 23:13:40. 855 D/XCDipHardware_einstein (1154): call processLoop.
01-01 23:13:40. 865 D/XCDipHardware_einstein (1154): [XCDipHardware] handlePreviewData call datacb.
01-01 23:13:40. 865 V/CameraClient (1154): _ data_cb
01-01 23:13:40. 865 D/CameraClient (1154): dataCallback (16, 0x10)
01-01 23:13:40. 865 D/CameraClient (1154): CameraClient: handlepreviewData.
01-01 23:13:40. 865 V/ICameraClient (1154): dataCallback
01-01 23:13:40. 865 D/ICameraClient (1154): Bp tid: 4090111104, pid: 1154.
01-01 23:13:40. 865 V/ICameraClient (2879): DATA_CALLBACK
01-01 23:13:40. 865 D/ICameraClient (2879): Bn tid: 2915554048, pid: 2879.
01-01 23:13:40. 865 D/Camera (2879): Camera: dataCallback
01-01 23:13:40. 865 D/Camera (2879): Callback tid: 2915554048, pid: 2879.
01-01 23:13:40. 865 I/SCREENSHOT_MAIN (2879): ScreenCaptureListener: postData. offset = 0, size = 1228800,

However, after the BpCameraClient in ICameraClient calls the remote ()-> transact (DATA_CALLBACK, data, & reply, IBinder: FLAG_ONEWAY) function, instead of calling DATA_CALLBACK of BnCameraClient: onTransact, BpCameraClient dataCallback call transact finished directly.
From this point of view, it seems that there is a problem with the Android Binder call!

For IBinder and its functions, find the following description on the Internet:

IBinder
Android. OS. IBinder
Class Overview
Base interface for a remotable object, the core part of a lightweight remote procedure call mechanic designed for high performance when Discovery Ming in-process and cross-process CILS. this interface describes the abstract protocol for interacting with a remotable object. do not implement this interface directly, instead extend from
Binder
.
The key IBinder API is
Transact ()
Matched
Binder. onTransact ()
. These methods allow you to send a call to an IBinder object and receive a call coming in to a Binder object, respectively. This transaction API is synchronous, such that a call
Transact ()
Does not return until the target has returned from
Binder. onTransact ()
. This is the expected behavior when calling an object that exists in the local process, and the underlying inter-process communication (IPC) mechanism ensures that these same semantics apply when going processing SS processes.

The system maintains a pool of transaction threads in each process that it runs in. these threads are used to dispatch all IPCs coming in from other processes. for example, when an IPC is made from process A to process B, the calling thread in A blocks in transact () as it sends the transaction to process B. the next available pool thread in B has es the incoming transaction, callbinder. onTransact () on the target object, and replies with the result Parcel. upon processing its result, the thread in process A returns to allow its execution to continue. in effect, other processes appear to use as additional threads that you did not create executing in your own process.

In the Binder communication process. onTransact () is called in two different processes. From the log I recorded, it is found that the transact () function runs in the system's mediaserver process, while the Binder. onTransact () should be running in my demo process. These APIs should have been synchronized. After the call thread of the mediaserver process sends the transaction to the demo process, itself should be blocked in the transact (). The idle thread in the demo process then receives the transaction and calls the Binder for the target object. onTransact (), and reply with the result Parcel. After receiving the message, the thread in the mediaserver process continues to run from the blocked place.

But now I found two problems in my demo program:
1. After the Transact () function is called, it is returned directly, and it is not blocked?
2. after the Transact () function is called, my demo process does not execute the Binder. the ontransact () function indicates that either my demo process or its related threads do not exist or are blocked?

Why is it not blocked after the transact () function is called?

Check the BpCameraClient: dataCallback () function in the ICameraClient. cpp file.

Figure 3 BpCameraClient: dataCallback () function <喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> Drawing/e3tbvY1rXV/drawing + L3iys2jujxiciAvPg0KPGltZyBhbHQ9 "here write picture description" src = "http://www.bkjia.com/uploads/allimg/150829/12310W1F-1.png" title = "\"/>
Figure 4 Binder parameter FLAG_ONEWAY

In Binder. add this parameter to transact (). This function is an asynchronous call and will return immediately. I did a test and removed this parameter, when I run it again, I find that the last line of log in Figure 3 is indeed not output. The BpBinder calling thread is blocked, but the demo program still has no image output! The reason for the Binder failure is not here!

Is the thread in the Demo process blocked or does not exist?

When the demo program is stuck, I use

Shell @ pitaya:/data/capture # debuggerd64ps | grep screenshot | busybox awk '{print $2}'
Sending request to dump task 2994.
Tombstone written to:/data/tombstones/tombstone_00

Print the status of the current demo process and find that the demo process has only one main thread.

Pid: 2994, tid: 2994, name: screenshot >>>/system/bin/screenshot <

The thread stack is as follows:

Backtrace:
#00 pc 0000000000019a5c/system/lib64/libc. so (syscall + 28)
#01 pc route 0000000202b0/system/lib64/libc. so (pthread_mutex_lock + 252)
#02 pc route 00000001efb4/system/lib64/libc. so (_ pthread_cond_timedwait_relative (pthread_cond_t *, pthread_mutex_t *, timespec const *) + 116)
#03 pc route 00000001f028/system/lib64/libc. so (_ pthread_cond_timedwait (pthread_cond_t *, pthread_mutex_t *, timespec const *, int) + 68)
#04 pc snapshot taken 31b4/system/bin/screenshot

It can be seen that it is currently blocked in gAvailableCV. waitRelative (gAvailableLock, 1000*1000000) function, so I used the pthread_create function to execute the Camera: connect () function in another thread.
It indicates that the Binder message on the Bn end is not processed in the main thread or in the thread we created using pthread_create. That is to say, there is no thread in our process that processes messages on the Binder Bp end and on the Bn end, how can we create these two threads?

In the Binder communication mechanism, if a Service wants to use Binder, it must do two things:
1. Enable the binder device;
2. Create a loose loop and wait for the request.

In the demo of the ICameraClient class and its derived class Camera and the Camera interface we call, we do not see the code for these two tasks,
Check out the Code related to Camera and ICameraClient:

class Camera :  public CameraBase
  
   , public BnCameraClient{}class BnCameraClient : public BnInterface
   
    {}class ICameraClient : public IInterface{}
   
  

It seems that BnInterface is on the Binder device.

template
  
   class BnInterface : public INTERFACE, public BBinder{public:    virtual sp
   
          queryLocalInterface(const String16& _descriptor);    virtual const String16&     getInterfaceDescriptor() const;protected:    virtual IBinder*            onAsBinder();};
   
  

After being cashed, it becomes

Class BnInterface: public ICameraClient, public BBinderBBinder, BpBinder. Does it correspond to BnXXX and BpXXX? Find the location it defines: BBinder (): Mexico TRAS (NULL) {// The Binder device is not enabled ?}

It indicates that the Binder mechanism did not enable the Binder device during its own initialization!

Go back to the Android project and find out how to use the Binder in main_mediaserver:

Figure 5 main_systemserver main Function

The first function to be called is ProcessState: self (), which is assigned to the proc variable. After the program runs successfully, proc automatically deletes the internal content, therefore, the previously allocated resources are automatically released.
ProcessState is in the ProcessState position in frameworks/native/libs/binder/ProcessState. cpp.

Sp
  
   
ProcessState: self () {if (gProcess! = NULL) return gProcess; // The AutoMutex _ l (gProcessMutex) will not be taken here for the first time; // The lock protects if (gProcess = NULL) gProcess = new ProcessState; // create a ProcessState object return gProcess; // here the pointer is returned, but the function returns the sp
   
    
, So the sp
    
     
It can be viewed as XXX}
    
   
  

Let's take a look at the ProcessState constructor.

ProcessState: ProcessState (): mDriverFD (open_driver () // a lot of Android code is written in this way, so I didn't see it calling a very important function, mVMStart (MAP_FAILED) // start address of the mapped memory, mManagesContexts (false), mBinderContextCheckFunc (NULL), mBinderContextUserData (NULL), mThreadPoolStarted (false), mThreadPoolSeq (1) {if (mDriverFD> = 0) {// BIDNER_VM_SIZE is defined as (1*1024*1024)-(4096*2) 1 M-8 K mVMStart = mmap (0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0); // you need to use man mmap by yourself, but it probably means // map fd to memory, in this way, memcpy and other operations in the memory are equivalent to write/read (fd }...}

Open_driver is to open the/dev/binder device. This is a virtual device set up by android in the kernel to complete inter-process communication, is a mechanism provided by the kernel.

Static int open_driver () {int fd = open (/dev/binder, O_RDWR); // open/dev/binder if (fd> = 0 ){.... size_t maxThreads = 15; // tells the kernel via ioctl that the fd supports a maximum of 15 threads. Result = ioctl (fd, BINDER_SET_MAX_THREADS, & maxThreads);} return fd ;}

Sp proc (ProcessState: self () here should be the operation to open the Binder device.
The link to the binder device is process-related. You can open one process.
So where can I perform similar message loop logoff operations?

sp
  
    proc(ProcessState::self());
  

This should be the operation to open the Binder device, so

ProcessState::self()->startThreadPool();IPCThreadState::self()->joinThreadPool();

It should be a message loop-like logoff operation!
Let's take a look at startThreadPool:

Void ProcessState: startThreadPool () {... spawnPooledThread (true);} void ProcessState: spawnPooledThread (bool isMain) {sp
  
   
T = new PoolThread (isMain); isMain is TRUE // create a Thread pool and run it. What is the same as java Thread. T-> run (buf);} PoolThread is derived from the Thread class. Will a Thread be generated at this time? Let's take a look at the construction of PoolThread and Thread: PoolThread (bool isMain): mIsMain (isMain) {} Thread: Thread (bool canCallJava) // The default value of canCallJava is true: mCanCallJava (canCallJava), mThread (thread_id_t (-1), mLock (Thread: mLock), mStatus (NO_ERROR), mitpending (false), mRunning (false ){}
  

At this time, no thread has been created, and then PoolThread: run is called. The actual run of the base class is called:

Status_t Thread: run (const char * name, int32_t priority, size_t stack) {bool res; if (mCanCallJava) {res = createThreadEtc (_ threadLoop, // The thread function is _ threadLoop this, name, priority, stack, & mThread );}}

Finally, the thread is created in the run function. Run from this main thread

IPCThreadState::self()->joinThreadPool();

New thread execution _ threadLoop

Int Thread: _ threadLoop (void * user) {Thread * const self = static_cast
  
   
(User); sp
   
    
Strong (self-> mHoldSelf); wp
    
     
Weak (strong); self-> mHoldSelf. clear (); do {... if (result &&! Self-> mExitPending) {result = self-> threadLoop (); Wow, call your own threadLoop }}
    
   
  

We are a PoolThread object, so we call the threadLoop function of PoolThread.

Virtual bool PoolThread: threadLoop () {// mIsMain is true. // And note that this is a new thread. // Therefore, a new IPCThreadState object will be created. (Do you remember the local storage of the thread? TLS), and then IPCThreadState: self ()-> joinThreadPool (mIsMain); return false ;}

JoinThreadPool is called for both the main thread and working thread. Let's see what it is!

void IPCThreadState::joinThreadPool(bool isMain){    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);    status_t result;    do {        int32_t cmd;        result = talkWithDriver();        result = executeCommand(cmd);    } while (result != -ECONNREFUSED && result != -EBADF);    mOut.writeInt32(BC_EXIT_LOOPER);    talkWithDriver(false);}

There is a loop, but it seems that two threads have executed this! There are two message loops.
Let's take a look at executeCommand.

Status_t IPCThreadState: executeCommand (int32_t cmd) {BBinder * obj; RefBase: weakref_type * refs; status_t result = NO_ERROR; case BR_TRANSACTION: {binder_transaction_data tr; result = mIn. read (& tr, sizeof (tr); // a command is generated, parsed to BR_TRANSACTION, and then read the subsequent information Parcel reply; if (tr.tar get. ptr) {// BBinder is used here. Sp
  
   
B (BBinder *) tr. cookie); const status_t error = B-> transact (tr. code, buffer, & reply, 0 );}}}
  

Let's take a look at what the BBinder functions do.

Status_t BBinder: transact (uint32_t code, const Parcel & data, Parcel * reply, uint32_t flags) {// call your onTransact function err = onTransact (code, data, reply, flags); return err ;}

BnCameraClient is derived from BBinder, so it will call its onTransact Function
Then, the onTransact function of BnCameraClient collects commands and distributes them to the Camera function of the derived class to complete the actual work.

From the above analysis, I need to call

sp
  
    proc(ProcessState::self());
  

To open the Binder device, you also need to call

ProcessState::self()->startThreadPool();IPCThreadState::self()->joinThreadPool();

To create a Binder Message Processing thread, which is a loop processing thread.

After the three sentences are added to the demo process, BpCameraClient can call BnCameraClient. In the serial port, enter:
Busybox ps-T command to view the thread status in the current demo process:

3151 0 0: 00/system/bin/screenshot
3152 0 0: 00 {Binder_1}/system/bin/Screen
3154 0 0: 00 {Binder_2}/system/bin/screenshot

It is found that the screenshot process does have three processes, two of which are the Binder threads, and the status information of the current demo process is further printed. It is found that there are three threads in the demo process:

5 pid: 2994, tid: 2994, name: screenshot >>>/system/bin/screenshot <
687 pid: 2994, tid: 2995, name: Binder_1 >>>/system/bin/screenshot <
2019 pid: 2994, tid: 2997, name: Binder_2 >>>/system/bin/screenshot <

Screenshot is the main demo thread, and the Binder_1 stack is as follows:

Backtrace:
#00 pc 000000000006104c/system/lib64/libc. so (nanosleep + 4)
#01 pc certificate 000000037e00/system/lib64/libc. so (sleep + 40)
#02 pc worker route 2c64/system/bin/screenshot
#03 pc route 000000028af0/system/lib64/libcamera_client.so (android: Camera: dataCallback (int, android: s
#04 pc route 00000002e8dc/system/lib64/libcamera_client.so (android: BnCameraClient: onTransact (unsigned
#05 pc route 000000021bac/system/lib64/libbinder. so (android: BBinder: transact (unsigned int, android: Pa
#06 pc route 00000002a04c/system/lib64/libbinder. so (android: IPCThreadState: executeCommand (int) + 876)
#07 pc route 00000002a22c/system/lib64/libbinder. so (android: IPCThreadState: getAndExecuteCommand () + 92)
#08 pc route 00000002a2a0/system/lib64/libbinder. so (android: IPCThreadState: joinThreadPool (bool) + 76)
#09 pc route 000000031bd0/system/lib64/libbinder. so
#10 pc route 0000000169c0/system/lib64/libutils. so (android: Thread: _ threadLoop (void *) + 208)
#11 pc route 00000001620c/system/lib64/libutils. so
#12 pc route 00000001f168/system/lib64/libc. so (_ pthread_start (void *) + 52)
#13 pc route 00000001b370/system/lib64/libc. so (_ start_thread + 16)

Binder_1 is the message processing thread of BBinder.
The Binder_2 stack is as follows:

Backtrace:
#00 pc 000000000006173c/system/lib64/libc. so (_ ioctl + 4)
#01 pc route 000000088a48/system/lib64/libc. so (ioctl + 100)
#02 pc route 0000000299a4/system/lib64/libbinder. so (android: IPCThreadState: talkWithDriver (bool) + 164)
#03 pc route 00000002a1e8/system/lib64/libbinder. so (android: IPCThreadState: getAndExecuteCommand () + 24
#04 pc route 00000002a2a0/system/lib64/libbinder. so (android: IPCThreadState: joinThreadPool (bool) + 76)
#05 pc route 000000031bd0/system/lib64/libbinder. so
#06 pc route 0000000169c0/system/lib64/libutils. so (android: Thread: _ threadLoop (void *) + 208)
#07 pc certificate 00000001620c/system/lib64/libutils. so
#08 pc route 00000001f168/system/lib64/libc. so (_ pthread_start (void *) + 52)
#09 pc 2017100000001b370/system/lib64/libc. so (_ start_thread + 16)

It should be the thread in which BpBinder sends messages to the Binder device.

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.