Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

Антон Дудаков Лаборатория встраиваемых автомобильных решений Как общаются приложения

Slide 3

Slide 3 text

› запуск приложениями друг друга (и получение результатов работы) › обмен уведомлениями о событиях › предоставление данных › предоставление функций › предоставление элементов пользовательского интерфейса Задачи решаемые взаимодействием 3

Slide 4

Slide 4 text

› startActivity, startActivityForResult › sendBroadcast › ContentProvider › AIDL (+Messenger) › Специализированные средства, обёрнутые в системные сервисы (widgethost, mediasession, remote controller, notification listener) API предоставляемый Anroid 4

Slide 5

Slide 5 text

Binder /dev/binder Под капотом 5

Slide 6

Slide 6 text

startActivityForResult 6 Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
 
 takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); 
 startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);

Slide 7

Slide 7 text

Binder на примере startActivityForResult 7 Activity (app1) ActivityManager Activity (app2) startActivityForResult startActivityForResult running setResult finish finishActivity onActivityResult

Slide 8

Slide 8 text

Binder на примере startActivityForResult 2 8 Activity ActivityManager Activity startActivityForResult running setResult finish attachApplication (ApplicationInterface) ActivityManager Proxy ActivityManager Stub startActivity startActivity Application Stub ActivityManager Proxy startProcess attachApplication scheduleLaunchActivity startActivity finishActivity finishActivity finishActivity Application Stub scheduleSendResult onActivityResult

Slide 9

Slide 9 text

Приложения и ActivityManager находятся в разных процессах 9 Activity ActivityManager startActivityForResult ActivityManager Proxy ActivityManager Stub . transaction(J) on Descriptor(X) startActivity Application Stub scheduleSendResult onActivityResult BinderDriver onTransaction(J) AppProxy transaction(K) on Descriptor(Y) onTransaction(K) binder binder binder binder

Slide 10

Slide 10 text

Binder на примере startActivityForResult 3 10 Activity ActivityManager Activity ActivityManager Proxy ActivityManager Stub Application Stub ActivityManager Proxy Application Stub BinderDriver startActivityForResult startProcess Zygote startActivity 2Application ThreadProxy 1Application ThreadProxy App1 App2 scheduleLaunchActivity startActivity setResult; finish finishActivity scheduleSendResult startActivity startActivity scheduleLaunchActivity scheduleLaunchActivity finishActivity finishActivity scheduleSendResult scheduleSendResult onResult

Slide 11

Slide 11 text

/frameworks/native/libs/binder/ProcessState.cpp android.os.TransactionTooLargeException 11 #define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2)) … // mmap the binder, providing a chunk of virtual address // space to receive transactions.
 mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);

Slide 12

Slide 12 text

› 1Mb на транзакцию › пользователь покидает ваше приложение › как следствие система вас может убить или пользователь просто не вернётся в него › передавать можно примитивы, String, Parcelable, Serializable и их списки › Основное назначение – запуск других activity, получение результата их работы по завершению Особенности startActivityForResult 12

Slide 13

Slide 13 text

sendBroadcast 13 Intent intent = new Intent();
 intent.setAction("com.example.broadcast.BROADCAST_ME");
 intent.putExtra("data","Hello world");
 sendBroadcast(intent);

Slide 14

Slide 14 text

sendBroadcast на схеме 14 app 1 Activity ActivityManager sendBroadcast getFromQueue ActivityManager Proxy ActivityManager Stub broadcastIntent broadcastIntent addToQueu deliver app 2 deliver repeat

Slide 15

Slide 15 text

› В системе всего три (4.2+) очереди бродкастов: 1. mStickyBroadcasts (Deprecated) 2. mFgBroadcastQueue 3. mBgBroadcastQueue sendBroadcast очереди 15

Slide 16

Slide 16 text

› 1Mb на транзакцию › время доставки Intent’а не гарантировано › полностью асинхронно › вы не знаете когда получатель(и) получит ваш Intent и как он на него ответит. И ответит ли ( кроме orderedBroadcast) › передавать можно примитивы, String, Parcelable, Serializable и их списки Особенности sendBroadcast 16

Slide 17

Slide 17 text

› сообщать о событиях, если время доставки вас не сильно беспокоит › или время доставки вас беспокоит чуть больше чем «не сильно» и приложение, которому вы отправляете находится в Foreground › registerReceiver 
 принимать сообщения от системы (CONNECTIVITY_ACTION, ACTION_HEADSET_PLUG, ACTION_MEDIA_MOUNTED, …) › Основное назначение – рассылка сообщений/ уведомлений Для чего подходит Broadcast 17

Slide 18

Slide 18 text

AIDL – Android Interface Definition Language IPC – InterProcess Communications RPC – Remote Procedure Call AIDL – термины 18

Slide 19

Slide 19 text

AIDL данные 1 19 // CLIENT Intent service = new Intent();
 service.setComponent(component);
 bindService(service, mServiceConnection, BIND_AUTO_CREATE);
 //… ServiceConnection mServiceConnection = new ServiceConnection() {
 
 void onServiceConnected(ComponentName name, IBinder service) {
 mService = ITestService.Stub.asInterface(service);
 SomeData someData = mService.getData(SIZE);
 mService.setData(getProcessedData(someData));
 unbindService(this);
 }
 
 void onServiceDisconnected(ComponentName name) {
 mService = null;
 }
 }; //SERVER class TestService extends Service {
 ITestService.Stub mBinder = new ITestService.Stub() { 
 SomeData getData(int listSize) {
 return new SomeData(listSize);
 }
 
 void setData(SomeData someData){
 someData = someData;
 }
 };
 }

Slide 20

Slide 20 text

AIDL данные 2 20 // ITestService.aidl
 package ru.example.testservice;
 
 import ru.example.testservice.SomeData;
 
 interface ITestService {
 SomeData getData(int listSize);
 void setData(in SomeData route);
 }
 // SomeData.aidl
 package ru.example.testservice;
 
 parcelable SomeData;

Slide 21

Slide 21 text

AIDL данные 3. Схема 21 Context App1 Service App2 ActivityManager ServiceConnection bindService(serviceConnection) Binder Driver Service.Proxy startService() Service.Stub new Service.Stub() setData() getData()

Slide 22

Slide 22 text

› Примитивы › String › Parcelable–объекты › IInterface › Списки поддерживаемых типов AIDL что можно передать 22

Slide 23

Slide 23 text

AIDL Callback 1 23 // ITestService.aidl
 package ru.example.testservice;
 
 import ru.example.testservice.SomeData;
 
 interface ITestService {
 SomeData getData(int listSize);
 void setData(in SomeData route);
 }
 // SomeData.aidl
 package ru.example.testservice;
 
 parcelable SomeData; // ISomeCallback.aidl
 package ru.example.testservice;
 
 interface ISomeCallback {
 void onFinish(boolean success);
 } // ITestService.aidl
 package ru.example.testservice;
 
 import ru.example.testservice.SomeData;
 import ru.example.testservice.ISomeCallback;
 
 interface ITestService {
 SomeData getData(int listSize);
 void setData(in SomeData route);
 
 void setCallBack( in ISomeCallback someCallback);
 }

Slide 24

Slide 24 text

AIDL Callback 2 24 // CLIENT ISomeCallback.Stub someCallback = new ISomeCallback.Stub() {
 void onFinish(boolean success) {/*.*/}
 }; ServiceConnection mServiceConnection = new ServiceConnection() {
 void onServiceConnected(ComponentName name, IBinder service) {
 mService = ITestService.Stub.asInterface(service);
 mService.setCallBack(someCallback);
 }
 
 void onServiceDisconnected(ComponentName name) {
 mService = null;
 }
 }; //... bindTestService(); //SERVER class TestService extends Service {
 ITestService.Stub mBinder = new ITestService.Stub() {
 SomeData getData(int listSize) {
 return new SomeData(listSize);
 }
 void setData(SomeData someData) {
 CurrentSomeData = someData;
 } 
 void setCallBack(ISomeCallback callback) {
 new Thread() {
 void run() {
 callback.onFinish(isEverythingOk());
 }
 }.start();
 }
 };
 //... }

Slide 25

Slide 25 text

AIDL Callback 3 25 Context App1 Service App2 ActivityManager ServiceConnection bindService(serviceConnection) Binder Driver Service.Proxy startService() Service.Stub new Service.Stub() setCallback(callback) CallbackStub CallbackProxy onFinish(boolean)

Slide 26

Slide 26 text

В качестве Callback можно использовать объект Messenger AIDL Callback 4.1 Messenger 26 // ITestService.aidl
 package ru.example.testservice;
 
 import ru.example.testservice.SomeData;
 
 interface ITestService {
 SomeData getData(int listSize);
 void setData(in SomeData route);
 void setMessenger(in Messenger messenger);
 } // Messenger.aidl
 package android.os;
 
 import android.os.Message;
 
 /** @hide */
 oneway interface IMessenger {
 void send(in Message msg);
 }

Slide 27

Slide 27 text

AIDL Callback 4.2 Messenger 27 // CLIENT 
 Messenger messenger = new Messenger(new Handler() {
 void handleMessage(Message msg) {
 showToast(msg.getData().getString("0"));
 }
 });
 ServiceConnection mServiceConnection = new ServiceConnection() { 
 void onServiceConnected(ComponentName name, IBinder service) {
 mService = ITestService.Stub.asInterface(service);
 mService.setMessenger(messenger);
 } //...
 }; //... bindTestService(); //SERVER ITestService.Stub mBinder = new ITestService.Stub() {
 // ..
 void setMessenger(Messenger messenger) {
 Message message = Message.obtain();
 Bundle bundle = new Bundle();
 bundle.putString("0", "Hello world");
 message.setData(bundle);
 messenger.send(message);
 }
 };


Slide 28

Slide 28 text

› для всего ;) › вызов методов другого приложение как синхронно, так и асинхронно › подписка на получение уведомлений без задержек (собственным Callback-объектом или используя Messenger или ResultReceiver) › передача и получение небольших (до 1Мб) объектов › Основное назначение – удалённый вызов процедур Для чего подходит AIDL 28

Slide 29

Slide 29 text

ContentProvider 29 // Client void onClick() {
 try (Cursor cursor = getContentResolver().query(uri, null, null, null, null)) {
 if (cursor != null && cursor.moveToFirst()) {
 byte[] blob = cursor.getBlob(cursor.getColumnCount() - 1);
 }
 } catch (Exception e) {
 }
 }
 
 ............... // Server Cursor query(@NonNull Uri uri, String[] projection, String selection,
 String[] selectionArgs, String sortOrder) {
 MatrixCursor cursor = new MatrixCursor(new String[]{"_ID", "blob"}, 0);
 cursor.newRow().add("0").add(Byte.MAX_VALUE);
 return cursor;
 }

Slide 30

Slide 30 text

ContentProvider2 30 Context App1 ContentProvider App2 ActivityManager query() ContentResolver acquireProvider() ContentProviderProxy Binder Driver ContentProviderProxy query() BulkCursor BulkCursorProxy moveToFirst() CursorWindow (parcelable) new CursorWindow() Anonymous Shared memory BLOCK 2MB Data new BulkCursor() Cursor BulkCursorProxy CursorWindow CursorWindow (parcelable) getData()

Slide 31

Slide 31 text

› 2Мб на каждую строку в курсоре › строк может быть сколько хочешь › запросы происходят синхронно › передавать можно примитивы, byte[], String. Для остальных данных выполняется toString() › а ещё есть метод call(), который возвращает Bundle › Основное назначение – передача данных Особенности ContentProvider 31

Slide 32

Slide 32 text

› AccountManager – место для хранения аккаунтов с возможностью поделиться данными аккаунтов › App Widgets – передача приложению реализующему AppWidgetHost (Launcher) своих View › MyService extends NotificationListenerService – в этом случае ваш сервис будет получать все публикуемые уведомления (разрешение включается отдельной галочкой) › remotecontroller (14 - 21) и mediasession (21+) – чтобы получить управление аудиосессиями нужно реализовать NotificationListenerService Спецсредства для взаимодействия 32

Slide 33

Slide 33 text

› startActivity – временно передать UI другому › sendBroadcast – сказать всем желающим что что-то случилось или узнать что что-то случилось › ContentProvider – поделиться или получить списки данных › AIDL – включить другое приложение в фоне, чтобы оно работало, мы бы им управляли, а оно бы нам ещё и присылало что-нибудь › Спецсредства – управление аккаунтами, рисование виджетов, чтение уведомлений, управление музыкой и много ещё чего другого не менее интересного… Выводы 33

Slide 34

Slide 34 text

Антон Дудаков Android разработчик, постоянный участник AndroidDev Podcast bwdude [email protected] Спасибо. Вопросы? bwdude