问题:
A进程调用B进程的b方法(AIDL实现的,B进程有个服务),B进程没有创建的情况下,B进程中是b方法先执行还是Application的onCreate方法先执行?如果b方法很耗时,A进程会被阻塞住吗
回答:
通过AIDL进行跨进程通信时,其底层依赖Binder驱动,客户端持有Binder代理对象向服务端的Binder对象发起请求,在上述问题中,如果A进程调用B进程的b方法,且B进程尚未创建,那么在发起调用时,会首先创建B进程,调用B进程Application的onCreate方法,随后成功获取B进程的Binder代理对象,通过Binder代理对象执行B方法。
B进程作为服务端进程,其向客户端提供两类方法,分别是同步方法和异步方法,针对同步方法而言,其会阻塞A进程的执行,直到结果返回,针对异步方法而言,其不会阻塞A进程执行,我们可以通过查看方法是否使用oneway修饰来确定该方法是否是异步方法,有oneway关键词修饰的是异步方法,所以B进程的b方法是否阻塞A进程完全取决于b方法是同步方法还是异步方法。
解析:
编写测试代码,指定Service在单独的进程运行,测试上述结论是否正确,代码片段如下:
1.MainApplication代码
public class MainApplication extends Application {
@SuppressLint("LongLogTag")
@Override
public void onCreate() {
// 在Application onCreate中打印当前进程名
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
Log.d("DEBUG-AIDL:MainApplication","Application onCreate called,processName is:"+getProcessName());
}
super.onCreate();
}
}
2.Service代码
public class BookManagerService extends Service {
private static final String TAG = "DEBUG-AIDL: " + BookManagerService.class.getSimpleName();
// 支持并发读写
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
private AtomicBoolean mIsServiceDestroyed = new AtomicBoolean(false);
private Binder mBinder = new IBookManager.Stub() {
@Override public List<Book> getBookList() throws RemoteException {
SystemClock.sleep(5000); // 延迟加载
return mBookList;
}
@Override public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
};
@Override public void onCreate() {
super.onCreate();
}
@Override public void onDestroy() {
mIsServiceDestroyed.set(true);
super.onDestroy();
}
private int num = 0;
@Override public IBinder onBind(Intent intent) {
return mBinder;
}
}
<!-- 声明Service在单独的进程运行 -->
<service android:name=".aidl.BookManagerService"
android:exported="true"
android:enabled="true"
android:process=":remote"></service>
3.Activity代码
public class MainActivity extends AppCompatActivity {
private static final String TAG = "DEBUG-AIDL: " + MainActivity.class.getSimpleName();
private IBookManager mRemoteBookManager;
private ServiceConnection mConnection = new ServiceConnection() {
@Override public void onServiceConnected(ComponentName name, IBinder service) {
IBookManager bookManager = IBookManager.Stub.asInterface(service);
Log.d(TAG,"获取到远端代理对象:"+bookManager);
try {
mRemoteBookManager = bookManager;
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override public void onServiceDisconnected(ComponentName name) {
mRemoteBookManager = null;
Log.e(TAG, "绑定结束");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main1);
bindService();
}
public void bindService() {
Intent intent = new Intent(this, BookManagerService.class);
Log.d(TAG,"调用bindService");
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
public void getBookList(View view) {
Toast.makeText(getApplicationContext(), "正在获取中...", Toast.LENGTH_SHORT).show();
List<Book> list = null;
try {
list = mRemoteBookManager.getBookList();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
Binder代理对象与服务端进程创建
运行程序,我们可以看到在获取Binder代理对象成功后,进程就已经创建完成了,相关日志输出如下:
Binder代理对象调用同步方法
以addBook方法为例,假设addBook在Server端耗时10s,修改addBook实现如下:
@Override public void addBook(Book book) throws RemoteException {
Log.d(TAG,"开始添加book");
SystemClock.sleep(10000);
mBookList.add(book);
Log.d(TAG,"添加book完成");
}
并在onServiceConnected中调用addBook方法,代码如下:
@Override public void onServiceConnected(ComponentName name, IBinder service) {
IBookManager bookManager = IBookManager.Stub.asInterface(service);
Log.d(TAG,"获取到远端代理对象:"+bookManager);
try {
mRemoteBookManager = bookManager;
Book newBook = new Book(3, "学姐的故事");
Log.d(TAG,"BookManager called addBook function start");
bookManager.addBook(newBook);
Log.d(TAG,"BookManager called addBook function end");
} catch (RemoteException e) {
e.printStackTrace();
}
}
运行后查看日志输出,可以看到
在同步调用情况下,onServiceConnected中由于addBook的调用阻塞了10秒
Binder代理对象调用异步方法
修改addBook函数声明,使用oneway关键词修改后,代码如下:
随后运行程序,得到的日志输出如下:
综上所述,在A进程调用B进程B方法的调用过程中,相关情况如下:
示例中相关代码改编自github.com/SpikeKing/w…,大家可以下载按本文中描述修改测试