검색결과 리스트
글
안드로이드 프레임워크 프로그래밍(26) [System Service에서 Activity 함수 호출하기]
안드로이드 AIDL을 사용하여 RPC통신을 통해 Application 단계에서 Framework 단계의 method를 호출하는 방법에 대해 알아본 바 있습니다. 이번 포스팅에서는 Framework 단계에서 Application의 Activity에 존재하는 method를 호출하는 방법에 대해 알아보도록 하겠습니다.
포스팅을 시작하기에 앞서 이전에 사용하였던 Application 단계에서 Framework 단계의 기능을 사용한 바 있습니다. 이에 대한 자세한 내용은 아래 포스팅을 참조해주시길 바랍니다. 또한 본 포스팅의 예제 또한 아래 포스팅의 것을 사용하였음을 알립니다.
안드로이드 프레임워크 프로그래밍(4) [시스템서비스 추가하기]
안드로이드 Application을 실행하였을 때 Framework 단계에서 실행하고자 하는 method를 onCreate() 단계에서 등록을 합니다. 그 이후 System Service에서 특정 부분을 호출 받았을 때 Application의 Activity 내에 있는 함수를 실행하는 과정을 구현할 것입니다.
1. AIDL을 통해 Callback 함수 등록 및 해제 함수를 만들어줍니다.
/frameworks/base/core/java/android/os/ITestService.aidl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | /* * aidl file : frameworks/base/core/java/android/os/ITestService.aidl * This file contains definitions of functions which are exposed by service */ package android.os; import android.os.IActivityServiceCallback; interface ITestService { /** * {@hide} */ void setValue(int val); void execCallback(int val); /** * Often you want to allow a service to call back to its clients. * This shows how to do so, by registering a callback interface with * the service. */ boolean registerCallback(IActivityServiceCallback cb); /** * Remove a previously registered callback interface. */ boolean unregisterCallback(IActivityServiceCallback cb); } | cs |
Activity에서 실행하고자 하는 method는 registerCallback() method를 통해 System Service에 등록할 수 있습니다. execCallback()함수는 이후 Application에서 RPC를 통해 호출을 받은 후 Callback 기능을 구현하기 위해 만든 함수입니다.
2. Activity로부터 호출하고자 하는 함수를 구현할 IActivityServiceCallback.aidl을 생성합니다.
/frameworks/base/core/java/android/os/IActivityServiceCallback.aidl
1 2 3 4 5 6 7 8 9 10 11 12 13 | package android.os; /** * Example of a callback interface used by IActivityService to send * synchronous notifications back to its clients. Note that this is a * one-way interface so the server does not block waiting for the client. */ oneway interface IActivityServiceCallback { /** * Called when the service has a new value for you. */ void callActivityMethod(int value); } | cs |
위의 과정에서 만들어진 callActivityMethod() method는 이후 Activity에서 Callback 방식으로 구현될 것입니다. 다음으로 System Serivce에서 위의 새로 생성한 함수들을 구현해 보도록 하겠습니다.
/frameworks/base/services/java/com/android/server/TestService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | /*TestService.java */ package com.android.server; import android.content.Context; import android.os.Handler; import android.os.IActivityServiceCallback; import android.os.ITestService; import android.os.Looper; import android.os.Message; import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.util.Log; public class TestService extends ITestService.Stub { private static final String TAG = "TestService"; private TestWorkerThread mWorker; private TestWorkerHandler mHandler; private Context mContext; RemoteCallbackList<IActivityServiceCallback> callbacks = new RemoteCallbackList<IActivityServiceCallback>(); public TestService(Context context) { super(); mContext = context; mWorker = new TestWorkerThread("TestServiceWorker"); mWorker.start(); Log.i(TAG, "Spawned worker thread"); } public boolean registerCallback(IActivityServiceCallback cb) throws RemoteException{ boolean flag = false; if(cb != null){ flag = callbacks.register(cb); } return flag; } public boolean unregisterCallback(IActivityServiceCallback cb) throws RemoteException{ boolean flag = false; if(cb != null){ flag = callbacks.unregister(cb); } return flag; } public void setValue(int val) { Log.i(TAG, "setValue " + val); Message msg = Message.obtain(); msg.what = TestWorkerHandler.MESSAGE_SET; msg.arg1 = val; mHandler.sendMessage(msg); } public void execCallback(int val){ Message msg = Message.obtain(); msg.what = TestWorkerHandler.CALLBACK; msg.arg1 = val; mHandler.sendMessage(msg); } private class TestWorkerThread extends Thread { public TestWorkerThread(String name) { super(name); } public void run() { Looper.prepare(); mHandler = new TestWorkerHandler(); Looper.loop(); } } private class TestWorkerHandler extends Handler { private static final int MESSAGE_SET = 0; private static final int CALLBACK = 1; @Override public void handleMessage(Message msg) { try { if (msg.what == MESSAGE_SET) { Log.i(TAG, "set message received: " + msg.arg1); } if (msg.what == CALLBACK) { int n = callbacks.beginBroadcast(); for(int i = 0; i < n ; i++){ try { Log.i(TAG, "callbacks.beginBroadcast()"); callbacks.getBroadcastItem(i).callActivityMethod(msg.arg1); } catch (RemoteException e) { e.printStackTrace(); } } callbacks.finishBroadcast(); } } catch (Exception e) { // Log, don't crash! Log.e(TAG, "Exception in TestWorkerHandler.handleMessage:", e); } } } } | cs |
RemoteCallbackList 클래스를 통해 Activity로부터 callback을 등록한 후 execCallback() method가 Application으로부터 호출되면 곧 System Service에서 등록한 callback을 실행하게 됩니다. 아래는 이를 구현한 Application 소스코드입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | package com.example.test; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.IActivityServiceCallback; import android.os.ITestService; import android.os.RemoteException; import android.os.ServiceManager; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.TextView; import android.util.Log; public class MainActivity extends Activity { private static final String DTAG = "HelloServer"; ITestService om; IActivityServiceCallback mCallback = new IActivityServiceCallback.Stub() { @Override public void callActivityMethod(int arg0) throws RemoteException { // TODO Auto-generated method stub final int value = arg0; mHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub setToast("callActivityMethod : " + value); } }); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); om = ITestService.Stub.asInterface(ServiceManager.getService("Test")); try{ Log.d(DTAG, "Going to call service"); om.setValue(20); om.registerCallback(mCallback); Log.d(DTAG, "Service called successfully"); }catch(Exception e){ Log.d(DTAG, "FAILED to call service"); e.printStackTrace(); } } public void OnClick(View v) throws RemoteException{ switch(v.getId()){ case R.id.button1: om.execCallback(100); break; } } void setToast(String msg) { Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); } protected void onDestroy(){ super.onDestroy(); try { om.unregisterCallback(mCallback); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } | cs |
위 함수를 실행하면 다음과 같은 결과를 얻으실 수 있습니다.
'안드로이드 > 프레임워크' 카테고리의 다른 글
안드로이드 프레임워크 프로그래밍(27) [Fedora에서 AOSP 안드로이드 운영체제 컴파일하기] (0) | 2015.12.31 |
---|---|
Windows 환경에서 fastboot를 통해 Android 이미지 포팅(Fastboot in Windows 7) (3) | 2015.11.22 |
Android에서 VSync 동작 원리 및 초기화 과정(5) (0) | 2015.09.20 |
안드로이드 프레임워크 프로그래밍(25) [Native 단계에서 Looper의 동작 원리] (0) | 2015.09.16 |
SurfaceFlinger에서 DispSyncSource의 초기화 과정 (0) | 2015.09.12 |