面试串讲013-A进程调用B进程的b方法,B进程没有创建的情况下,B进程中是b方法先执行还是Application的onCreate先?

110 阅读3分钟

问题:

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代理对象成功后,进程就已经创建完成了,相关日志输出如下:

mianshi013-1

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();
     }
 }

运行后查看日志输出,可以看到

mianshi013-2

在同步调用情况下,onServiceConnected中由于addBook的调用阻塞了10秒

Binder代理对象调用异步方法

修改addBook函数声明,使用oneway关键词修改后,代码如下:

mianshi013-3

随后运行程序,得到的日志输出如下:

mianshi013-4

综上所述,在A进程调用B进程B方法的调用过程中,相关情况如下:

A进程调用B进程b方法

示例中相关代码改编自github.com/SpikeKing/w…,大家可以下载按本文中描述修改测试