안드로이드 프레임워크 프로그래밍(4) [시스템서비스 추가하기]

안드로이드/프레임워크 2015. 1. 24. 04:13

 안드로이드 시스템 서비스란 운영체제가 동작하는 동안 수행할 수 있도록 구성된 어플리케이션 구성요소로 메시지 표시와 같이 시스템의 기본적인 기능들을 제공한다. 이러한 기능들을 활용하여 안드로이드 기기에서 동작하는 서비스를 개발하기 위한 클래스의 집합을 프레임워크라 한다. 본 포스팅은 이러한 시스템서비스를 추가하여 프레임워크의 동작 원리를 이해하는 것을 목표로 한다.


 다음은 서비스 레이어의 구조를 나타낸 것이다.

 


 상단의 Application에서 시스템서비스를 호출하면 해당 기능을 System Server에서 실행한다. 이 때 각 프로세스 간의 통신이 이루어져야 하는데 이는 IPC 또는 RPC 방식으로 이루어진다. Application과 System Server 사이에 있는 AIDL은 Application이 System Server로부터 해당 기능을 실행하는 프로세스를 호출할 수 있는 Interface를 제공하는 역할을 한다.


다음은 예제를 다루어 보도록 한다.


1. 시스템 서비스를 추가한다. 아래의 코드를 다음 경로에 생성한다.

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
/*TestService.java */
package com.android.server;
import android.content.Context;
import android.os.Handler;
import android.os.ITestService;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
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;
    public TestService(Context context) {
        super();
        mContext = context;
        mWorker = new TestWorkerThread("TestServiceWorker");
        mWorker.start();
        Log.i(TAG, "Spawned worker thread");
    }
 
    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);
    }
 
    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;
        @Override
        public void handleMessage(Message msg) {
            try {
                if (msg.what == MESSAGE_SET) {
                    Log.i(TAG, "set message received: " + msg.arg1);
                }
            } catch (Exception e) {
                // Log, don't crash!
                Log.e(TAG, "Exception in TestWorkerHandler.handleMessage:", e);
            }
        }
    }
}
 
cs


2. 추가로 만든 서비스를 등록한다.

frameworks/base/services/java/com/android/server/SystemServer.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
 
......
 
    if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
        //Added code(363 line)
        try{
            Slog.i(TAG, "Test Service");
            ServiceManager.addService("Test"new TestService(context));
        } catch (Throwable e){
            Slog.e(TAG, "Failure starting TestService Service", e);
        }
 
            //if (!disableNonCoreServices) { // TODO: View depends on these; mock them?
            if (true) {
                try {
                    Slog.i(TAG, "Input Method Service");
                    imm = new InputMethodManagerService(context, wm);
                    ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm);
                } catch (Throwable e) {
                    reportWtf("starting Input Manager Service", e);
                }
 
                try {
                    Slog.i(TAG, "Accessibility Manager");
                    ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
                            new AccessibilityManagerService(context));
                } catch (Throwable e) {
                    reportWtf("starting Accessibility Manager", e);
                }
            }
        }
......
cs

3. aidl을 추가하여 애플리케이션에서 추가된 서비스에 접근할 수 있는 인터페이스를 만든다.

frameworks/base/core/java/android/os/ITestService.aidl

1
2
3
4
5
6
7
8
9
10
11
/*
* aidl file : frameworks/base/core/java/android/os/ITestService.aidl
* This file contains definitions of functions which are exposed by service
*/
package android.os;
interface ITestService {
/**
* {@hide}
*/
    void setValue(int val);
}
cs

4. 추가한 aidl 파일을 등록한다.

frameworks/base/Android.mk

1
2
3
4
5
6
7
8
/*
 * open frameworks/base/Android.mk and add following line
 */
......
core/java/android/os/IPowerManager.aidl \
core/java/android/os/ITestService.aidl \
core/java/android/os/IRemoteCallback.aidl \
......
cs


5. 변경사항을 적용하기 위해 소스코드를 Build 한다. 빌드 방법은 아래 블로그를 참조한다.

http://elecs.tistory.com/59


6. Build가 완료되면 새로 수정된 프레임워크 라이브러리를 추출한다. 라이브러리는 다음 경로에서 구할 수 있다.

out/target/common/obj/JAVA_LIBRARIES

자바 라이브러리들을 확인할 수 있다. 우리들이 새로 추가한 시스템 서비스는 framework_intermediate 폴더 내에 있다.


폴더 내에 classes.jar 파일이 있는데 이 안에 우리들이 만든 서비스가 들어있다. 이를 직접 확인해보면


class 파일이 내부에 있는 것을 확인할 수 있다. 이것이 안드로이드 기기 전원이 ON 상태인 동안 백그라운드에서 기기가 OFF될 때까지 계속 실행된다.


7. 이제 이를 활용한 애플리케이션을 제작해 보도록 하자. 새로운 프로젝트를 생성한 후 위에서 찾은 라이브러리를 추가한다.

Eclipse에서 Project -> Properties를 실행한다.


Java Build Path -> Libraries에 들어가면 현재 안드로이드 프로젝트 내에 있는 라이브러리들을 볼 수 있다. 위에서 확인하였던 라이브러리를 추가하기 위해 오른쪽 메뉴에 있는 "Add External JARs..."를 클릭한다.



해당 경로로 이동한 후 Classes.jar 파일을 선택한 후 확인 버튼을 누르면



위에서 보는 바와 같이 classes.jar이 추가된 것을 확인할 수 있다. OK버튼을 눌러 설정을 적용한다.


8. 이제 MainActivity.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
package com.example.test;
 
import android.app.Activity;
import android.os.Bundle;
import android.os.ITestService;
import android.os.ServiceManager;
import android.view.Menu;
import android.view.MenuItem;
import android.util.Log;
 
 
public class MainActivity extends Activity {
    private static final String DTAG = "HelloServer";
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        ITestService om = ITestService.Stub.asInterface(ServiceManager.getService("Test"));
        try{
            Log.d(DTAG, "Going to call service");
            om.setValue(20);
            Log.d(DTAG, "Service called successfully");
        }catch(Exception e){
            Log.d(DTAG, "FAILED to call service");
            e.printStackTrace();
        }
        
    }
 
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
 
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}
cs


9. 안드로이드 기기에 어플리케이션을 설치한 후 실행하면 LogCat에 다음과 같은 결과가 나타나는 것을 확인할 수 있다.




출저 : Android-Adding SystemService

http://processors.wiki.ti.com/index.php/Android-Adding_SystemService

300x250