Marshmallow nexus4 cover

AOSP로 넥서스4에 최신 마시멜로우 올리기

이 글은 차영호 (Youngho Cha)님이 넥서스 4에 안드로이드 6.0을 포팅한 이야기를 정리한 것입니다.


난 더 이상 넥서스가 아니에요. 넥서스 4

Nexus 4를 사용한 이후 저는 넥서스를 쓴다는 자부심을 항상 가지고 있었습니다. 제가 쓰던 넥서스 4는 2012년에 출시되었는데요. Android 4.2를 시작으로 4.3, 4.4, 5.0, 5.1 버전 등 주요 안드로이드 버전과 함께 해왔습니다. 그런데 올해 발매된 안드로이드 6.0은 안타깝게도 제 폰을 지원하지 않았습니다.

아쉬웠던 중 Dmitry Grinberg가 안드로이드 6.0을 Nexus 4 에 올렸다는 이야기를 들었습니다.

그런데 이건 전혀 제가 원하는 것이 아니었죠. 저는 제가 원하는 것을 직접 만들기로 결정하였습니다. 제 목표는 넥서스다운 안드로이드 6.0을 설치하는 것이고 이 단계가 끝나면 좀더 나은 기능을 추가할 것입니다.

AOSP가 무엇인가요?

Android Open Source Project (AOSP)는 다들 한번 씩은 들어본 것 같은데 자세히는 모르는 것같습니다. 대부분의 개발자는 개발자 사이트에만 들어가보았지 AOSP 사이트에는 들어가보지 않은 것 같습니다. 주소가조금 긴데 이 사이트는 http://s.android.com/ 이라는 주소로 좀더 간편하게 들어갈 수 있어요.(마찬가지로 http://d.android.com 으로도 개발자 사이트에 들어갈 수 있습니다.)

AOSP에 해당하는 프로젝트는 보통 사람들이 생각하는 범위보다는 넓습니다. 안드로이드는 OS만 오픈되어 있는게 아니라 SDK, 에뮬레이터, NDK, 안드로이드 스튜디오, 문서, Nexus 9의 보안 영역인 Trust Zone, Brillo 등이 공개되어 있어요. 아직 Brillo는 정식으로 공개되지 않았는데 현재 작업 수준은 꽤 높은 단계로 진행된 것 같습니다.

AOSP를 빌드하는 법은 문서에 상세히 설명되어 있는데요. 빌드할 수 있는 단말은 제한되어 있는데 넥서스, 소니의 일부 단말, 기타 소수 단말만 AOSP를 통해 빌드할 수 있어요.

Manufacture Product name Hardware Product Nexus Product
Huawei Nexus 6P angler? ? ?
LG Nexus 5X bullhead bullhead bullhead
Motorola Nexus 6 shamu shamu shamu
LG Nexus 5 hammerhead hammerhead hammerhead
ASUS Nexus 7(2013) flo, deb flo, deb razor, razorg
LG Nexus 4 mako mako occam
Samsung Galaxy Nexus tuna magruo, toro yakju, takju, mysid
Samsung Nexus S herring crespo soju

이런 개발 뉴스를 더 만나보세요

AOSP에서 Nexus 5를 빌드하려면 Nexus 5를 찾으면 안되고 hammerhead를 찾아야 합니다. 저는mako를 검색했죠. 하드웨어 코드 네임들은 수중에 사는 대형 동물이라는 공통점이 있습니다. 처음에는어류인 줄 shamu가 범고래 종류이기 때문에 전체가 어류는 아니죠. Asus의 flodeb의의미하는 바는 모르겠어요. 저희가 Asus에서 검색할 것은 프로덕트 코드 네임입니다. Neuxs S를 빌드하기 위해서는 crespo를 찾아야 하는 거죠. 이 명칭은 하드웨어 코드 네임과 같은 경우도 있지만 조금씩 다른 경우도 있습니다. 프로덕트 코드 네임은 일종의 레시피고 이를 이용해서 빌드하면 특정하드웨어에서 딱 맞는 안드로이드 바이너리가 만들어집니다. 참고로 에물레이터도 바다 생물인데요. 현재 에뮬레이터는 goldfish이고 새로 개발 중인 에물레이터는 ranchu에요.

그런데 넥서스 팩토리 이미지들은 프로덕트 코드 네임과 다른 프로덕트 코드 네임을 가지고 있습니다.넥서스 5 이후에는 같은 이름인데 이전에는 다르죠. 삼성에서 출시된 두개의 단말기는 한국의 술로 되어있고 넥서스 4와 7을 합치면 Occam’s Razor라는 점입니다. 이 구글의 센스일까요?

넥서스처럼 빌드하기

구글이 팩토리 이미지를 빌드하기 위해 사용하는 레시피가 다릅니다. 저는 이 둘의 차이에 주목하고 차이를 줄이려고 합니다. 차이점을 알기 위해서 먼저 파일 단위로 비교를 하였습니다.

팩토리 이미지에 들어있는 파일들은 너무 많기 때문에 중략을 했습니다. 실제 부피는 두배 이상입니다.

조금 더 쉽게 보기 위해 일부 내용을 도표로 정리하였습니다. 이전에 Browser에서 처리하던 인텐트를 이제는 Chrome이 같은 방법으로 처리합니다. 마찬가지로 AOSP 앱에 있던 앱과 동일한 인텐트들을 구글 앱들이 동일한 인텐트를 처리합니다.

그리고 구글 앱들은 공통적으로 플레이 서비스를 사용합니다. AOSP 앱들은 플레이 서비스를 사용하지 않습니다.

우리가 빌드한 AOSP 이미지를 넥서스와 비슷하게 빌드하려면 결국 플레이 서비스와 구글 앱들이 필요합니다. AOSP에 구글 앱들을 설치하더라도 실제 넥서스와 비슷하지 않기 때문에 통합을 위해서는 시스템 프로퍼티를 변경해야 합니다.

수정해야 하는 시스템 프로퍼티

  • /root/default.prop
  • /system/build.prop

AOSP와 팩토리 이미지에서 다른 앱

  • /system/framework/framework-res.apk
  • /system/priv-app/SettingsProvider.apk
  • /system/priv-app/Settings.apk
  • /system/priv-app/SystemUI.apk
  • /system/priv-app/TeleService.apk

위의 다섯 앱들은 AOSP와 팩토리 이미지 간에 차이가 있는데 놀랍게도 소스 코드는 동일합니다. 소스 코드는 같지만 구성에 의해 차이가 발생한 것이지요.

그 차이를 알기 위해 aapt 도구를 사용합니다. aapt는 일반적으로 안드로이드 빌드 툴에 의해 apk 파일을 만들기 위해 사용되지만 apk를 디버깅을 하기 위해도 사용할 수 있습니다.

$ aapt d --values resources framework-res.apk

spec resource 0x01040029 android:string/default_sms_application: flags=0x00000000
resource 0x01040029 android:string/default_sms_application: t=0x03 d=0x00001e00 (s=0x0008 r=0x00)
          (string8) "com.android.mms"

저는 모든 리소스들을 덤프를 떠서 차이 나는 값들을 추출해냈습니다. 이제 이 값을 가지고 해당하는 값을 바꾸려고 하는데 저는 유지 보수 가능한 방법을 찾고 싶었습니다. 소스 코드를 수정하지 않고 모든 문제를 풀고 싶었습니다.

먼저 상수 교체를 위해서는 빌드 설정을 오버라이드 하는 방법을 사용했습니다. 아래는 실제 수정이 아니라 예제인데요. 저는 데이터 로밍이 비용이 들기 때문에 비활성화 시켜야 했고 아래의 항목을 오버라이드하는 식으로 사용합니다.

PRODUCT_PROPERTY_OVERRIDES := \
	ro.com.android.dataroaming=false \

리소스 교체를 위해서는 아래의 항목을 오버라이드 했습니다.

PRODUCT_PACKAGE_OVERLAYS := \
	device/lge/occam/overlay

이렇게 패키지를 오버라이드하면 빌드 과정에 아래와 같이 변경됩니다.

out-occam-user/host/linux-x86/bin/aapt package blahblah
     -S device/lge/occam/overlay/frameworks/base/core/res/res
     -S device/lge/mako/overlay/frameworks/base/core/res/res
     -S frameworks/base/core/res/res

먼저 포함된 -S 옵션 순으로 포함이 되고 뒤의 옵션에 있는 충돌되는 경우 드로어블이 충돌되면 통채로 바꾸고 XML 파일인 경우 엘리먼트 단위로 먼저 적용된 리소스를 우선해서 적용합니다. 파일 전체가 아니라 엘리먼트 단위로 머지하기 때문에 수정하기는 상당히 쉽습니다.

앱의 대체를 위해서는 LOCAL_OVERRIDES_PACKAGES를 이용합니다.

include $(CLEAR_VARS)
LOCAL_MODULE := Chrome
LOCAL_SRC_FILES := com.android.chrome.apk
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_TAGS := optional
LOCAL_OVERRIDES_PACKAGES := Browser
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_MODULE_OWNER := google
include $(BUILD_PREBUILT)
PRODUCT_PACKAGES := \
	Chrome \

Browser는 더 이상 설치되지 않고 Chrome 앱이 성공적으로 설치됩니다.

빌드 과정을 보면 팩토리 이미지와 차이를 느낄 수 없습니다.

Nexus4에 바이너리를 올려보면 진짜 넥서스 팩토리 롬 처럼 동작하며 경이로운 배터리 효율도 같이 확인 할 수 있습니다.

넥서스를 넘어

이제는 팩토리 넥서스 롬을 넘어 더 나은 경지로 올라가 봅시다. 혹시 넥서스 4가 LTE 모뎀을 탑재하고 있다는 사실을 아십니까? LTE가 소프트웨어 적으로 비활성화 되어 있고 이를 활성화 시키면 미국에서 LTE를 사용할 수 있습니다. 이를 활성화시키기 위해서는 소스 코드의 수정은 필요하지 않으며 프로퍼티와 리소스만 변경하면 됩니다. 아쉽게도 밴드 4만 지원하기 때문에 밴드 4가 지원되지 않은 지역에서는 쓸 수 없습니다.

저는 성능에서도 좀더 나아가고 싶었습니다. 퀄컴에서 bionic에 대해 작업한 내용이 AOSP 리뷰 시스템에 올라왔습니다. memcpy등이 1.3 ~ 1.5배 정도로 증가했다고 하더군요.

넥서스는 버튼이 별로 없는 편인데요. 이번 새로 나온 넥서스 단말기 들은 파워 버튼을 두번 눌러서 카메라를 켜는 기능이 적용되어 있습니다. AOSP 코드를 확인해보시면 해당 코드가 없다는 것을 알 수 있습니다. PhoneWindowManager 코드를 살펴보면 이 기능의 구현이 어렵지 않아 보입니다.

private void powerMultiPressAction(long eventTime, boolean interactive, int behavior) {
    switch (behavior) {
        case MULTI_PRESS_POWER_NOTHING:
            break;
        case MULTI_PRESS_POWER_THEATER_MODE:
            if (!isUserSetupComplete()) {
                Slog.i(TAG, "Ignoring toggling theater mode - device not setup.");
                break;
            }
            if (isTheaterModeEnabled()) {
                Slog.i(TAG, "Toggling theater mode off.");
                Settings.Global.putInt(mContext.getContentResolver(),
                        Settings.Global.THEATER_MODE_ON, 0);
                if (!interactive) {
                    wakeUpFromPowerKey(eventTime);
                }
            } else {
                Slog.i(TAG, "Toggling theater mode on.");
                Settings.Global.putInt(mContext.getContentResolver(),
                        Settings.Global.THEATER_MODE_ON, 1);
                if (mGoToSleepOnButtonPressTheaterMode && interactive) {
                    mPowerManager.goToSleep(eventTime,
                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
                }
            }
            break;
        case MULTI_PRESS_POWER_BRIGHTNESS_BOOST:
            Slog.i(TAG, "Starting brightness boost.");
            if (!interactive) {
                wakeUpFromPowerKey(eventTime);
            }
            mPowerManager.boostScreenBrightness(eventTime);
            break;
    }
}

여러번 터치를 했을 때를 위한 기능이 있는데요. 이 코드는 안드로이드 웨어 사용자를 위한 극장 모드 코드입니다. 이 코드를 조금 변경해서 우리 목표를 달성해봅시다. MULTI_PRESS_POWER_BRIGHTNESS_BOOST 밑에 우리가 필요한 기능을 넣읍시다.

case MULTI_PRESS_POWER_LAUNCH_CAMERA:
    Slog.i(TAG, "Launching camera by power button.");
    if (!mCameraLensCoverState != CAMERA_LENS_COVERED) {
        if (!interactive) {
            wakeUpFromPowerKey(eventTime);  
        }
        launchCamera();
    }
    break;

삼성의 갤럭시 S 시리즈에 있는 홈 버튼 더블 클릭으로 카메라 뜨는 기능도 이런 방법으로 쉽게 구현할 수 있습니다.

용량의 문제는 없나요?

빌드 과정에서 시스템 파티션 용량의 한계로 모든 구글 앱을 이미지에 올리지 못했습니다. 넥서스 5의 팩토리 이미지를 확인해보면 시스템 파티션의 용량 제한 때문에 큰 용량의 앱에 대해 우회 방법을 사용하는 것을 볼 수 있습니다. 넥서스 5의 경우에 기본 설치되는 앱은 실제 앱의 APK가 아닌 더미 APK가 설치되어 플레이 스토어로 안내하는 것을 볼 수 있습니다.

추가적으로 기본 클래스 패스를 제외한 ODEX 파일들을 제거하였습니다. 첫번째 부팅 과정이 더 오래 걸리겠지만 처음 부팅이 완료된 후 정상적으로 사용할 수 있습니다. 첫번째 부팅이 5분에서 10분이 걸리는 것이 안타깝지만 이 정도면 만족할 수 있을 것 같습니다. 일반적인 Nexus 4 커스텀 롬들은 수십분 단위로 걸리는 것 같습니다.

그리고 저널링 영역을 제거하였습니다. 시스템 영역은 읽기 전용인데 기존 넥서스 4에는 저널링 영역을 포함하고 있었습니다. 이 작업을 통해 수십 메가를 추가로 확보할 수 있었습니다.

AOSP로 정말 팩토리 이미지를 만들 수 있어요?

저는 처음에는 혹시 구글의 팩토리 이미지가 AOSP가 다른 것이 아닌가 의심을 했었는데 이 작업을 통해서 팩토리 이미지와의 차이만 안다면 소스의 수정없이 팩토리 이미지를 동일하게 만들 수 있다는 것을 알 수 있었습니다.

실제 작업한 내용은 제 작업 리포지토리에서 보실 수 있습니다.

  • https://github.com/ganadist/device_lge_mako
  • https://github.com/ganadist/device_lge_occam
  • https://github.com/ganadist/gms_addon/tree/android-6.0.0_r1

한가지 아쉬운 점은 이번에 새로 공개된 Nexus 5X는 AOSP의 코드와 다르다는 점입니다. 보통은 리소스의 값이 바뀔 수는 있지만 키가 바뀔 일은 없습니다. 그런데 Nexus 5X의 팩토리 이미지는 추가된 키가 있습니다. 안드로이드 버전이 올라간 것으로 추정하고 있습니다. 저는 안드로이드의 새버전 소스 코드가 빠른 시간 내에 공개되길 기대하고 있습니다.

컨텐츠에 대하여

이 컨텐츠는 저자의 허가 하에 이곳에서 공유합니다.

Realm Team

Realm의 미션은 더 나은 앱을 빠르게 개발할 수 있도록 돕는 것입니다. 이를 위해 저희는 개발자들이 실시간 협업, 가상 현실, 라이브 데이터 동기화, 오프라인 경험, 메시징 등 정교하고 강력한 기능을 쉽게 개발할 수 있도록 하는 개발 도구와 플랫폼을 제공하고 있습니다.

저희는 모바일 인터넷이 수많은 사용자와 보다 많은 디바이스가 속한 개방형 네트워크와 이들 간의 실시간 상호 작용으로 진화할 것이라고 믿으며, 개발자가 이같은 방향으로 발전할 수 있도록 돕기 위해 저희 제품들을 개발하고 있습니다.

4 design patterns for a RESTless mobile integration »

close