AsInterface parsing in Binder, binderasinterface
When AIDL is used for communication, an asInterface function is generated in Stub class. The example in Android development art exploration is analyzed. The source code of the asInterface function is:
1 /** 2 * Cast an IBinder object into an com.willhua.demoaidl.aidl.IBookManager 3 * interface, generating a proxy if needed. 4 */ 5 public static com.willhua.demoaidl.aidl.IBookManager asInterface( 6 android.os.IBinder obj) { 7 if ((obj == null)) { 8 return null; 9 }10 android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);11 if (((iin != null) && (iin instanceof com.willhua.demoaidl.aidl.IBookManager))) {12 return ((com.willhua.demoaidl.aidl.IBookManager) iin);13 }14 return new com.willhua.demoaidl.aidl.IBookManager.Stub.Proxy(obj);15 }
We know that asInterface is used to return different instance objects based on whether the call belongs to the same process,However, many children's shoes may not be very clear about how the process is implemented and what is returned. I will share my understanding on this issue.Obviously, the Code shows that the key to determining which object to return is the return result of obj. queryLocalInterface (DESCRIPTOR.
Next we will use the actual DEMO to understand the process. The Code is based on the example in Android development art exploration.
There are two main things in the DEMO: MainActivity and BookService. MainActivity goes to bind BookService, and BookService sets android in Manifest: process to run the same process and process as MainActivity respectively.
Main Code:
public class BookService extends Service { private Binder mBinder = new IBookManager.Stub() { ... }; @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub LOG("BookService onBind mBinder:" +mBinder.getClass().getName() + " Process:" + Process.myPid()); return mBinder; }}
public class MainActivity extends Activity{ private IBookManager mService; private Button mQuery; private TextView mOutInfo; ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); connectService(); } private void connectService(){ Intent intent = new Intent(getApplicationContext(), BookService.class); bindService(intent, new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub } @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub LOG("onServiceConnected " + service); mService = IBookManager.Stub.asInterface(service); } }, BIND_AUTO_CREATE); } ...}
public static abstract class Stub extends android.os.Binder implements com.willhua.demoaidl.aidl.IBookManager { private static final java.lang.String DESCRIPTOR = "com.willhua.demoaidl.aidl.IBookManager"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.willhua.demoaidl.aidl.IBookManager * interface, generating a proxy if needed. */ public static com.willhua.demoaidl.aidl.IBookManager asInterface( android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.willhua.demoaidl.aidl.IBookManager))) { return ((com.willhua.demoaidl.aidl.IBookManager) iin); } return new com.willhua.demoaidl.aidl.IBookManager.Stub.Proxy(obj); }...}
Some source code of androd. OS. Binder:
public class Binder implements IBinder { //... /** * Convenience method for associating a specific interface with the Binder. * After calling, queryLocalInterface() will be implemented for you * to return the given owner IInterface when the corresponding * descriptor is requested. */ public void attachInterface(IInterface owner, String descriptor) { mOwner = owner; mDescriptor = descriptor; } /** * Use information supplied to attachInterface() to return the * associated IInterface if it matches the requested * descriptor. */ public IInterface queryLocalInterface(String descriptor) { if (mDescriptor.equals(descriptor)) { return mOwner; } return null; } //... final class BinderProxy implements IBinder { //... public IInterface queryLocalInterface(String descriptor) { return null; } //... }}
Through the LOG, we found that in the onServiceConnected function, if MainActivity and BookService are in the same process, the printed log is:
If the MainActivity is different from the BookService process, and the MainActivity is bound to the BookService service across processes, the printed log is:
Analyze the same process first,
In the same process, the type of the service object received by onServiceConnected is BookServices $1. We know that $ represents the internal class in BookServices, and in the definition of BookServices, we only defined an IBookManager in the initialization of mBinder. the subclass of Stub (), that is, IBookManager received in onServiceConnected during the same process. stub () type. The queryLocalInterface method of IBookManager. Stub () extenders android. OS. Binder implements IBookManager comes from the superclass android. OS. Binder. For the descriptor passed in the method, we can see through the asInterface code that it is the DESCRIPTOR defined in Stub, while the mDescriptor defined in the Binder is assigned in the attachInterface function, the attachInterface function is called in the Stub constructor.
this.attachInterface(this, DESCRIPTOR);
The call in onServiceConnected is:
mService = IBookManager.Stub.asInterface(service);
Note that sercice is IBookManager. Stub, so that we can know that,
if (mDescriptor.equals(descriptor))
If both the mDescriptor and descriptor in the statement are the DESCRIPTOR defined in IBookManager. Stub, queryLocalInterface returns mOwer. So what is mOwer? Careful kids shoes may already know the answer. When the Stub constructor calls attachInterface, it has assigned a value to mOwer and assigned this value, that is, the Stub object itself! Back to the logic of asInterface, we can conclude that when the process is the same, the returned result of calling asInterface is the Stub object, which is actually the mBinder returned in onBind.
Analyze the situation of cross-process calls
The preceding log shows that the service received in onSericeConnected is android during cross-Process calling. OS. the BinderProxy type, and the source code above has been given, BinderProxy is the final class, and its queryLocalInterface method directly returns null, combined with the asInterface code logic, it will know that it returns IBookManager. stub. proxy object. It is concluded that Stub is returned when the asInterface is called during the same process. proxy object.
At this point, the question mentioned in the beginning should be clear. However, another new question is raised: Why does onServiceConnected receive OS. BinderProxy during cross-process scheduling, while IBookManager. Stub is received when the same process is called?
Listen again...