이 글은 안드로이드 레퍼런스 폰의 팩토리 이미지를 빌드하는 방법에 관하여 간단히 설명해 놓은것입니다.


솔직히 설명할 필요도 없이 아래 세 개의 링크만 클릭하면 모든 설명들이 자세하게 되어 있지만, 약간의 예외 및 기타 잡다한 참견들을 추가하도록 하겠습니다. ^^;


https://source.android.com/setup/build/initializing

https://source.android.com/setup/build/downloading

https://source.android.com/setup/build/building



참고로 위 세 개의 링크만 잘 읽어보면, 쉽게 빌드할 수 있지만, 알고보면, 그렇게 쉽지 않은 이유는 조그마한 환경변수나 버전이 하나만 틀어져버려도 에러가 발생할 수 있기 때문입니다.

그래서, 필자도 처음에는 Mac OS 에서 빌드를 시작해서 결국, Mac OS 위 VmWare Fusion 30일용 + Ubuntu 14.04  에서 몇 번 실패한 끝에 겨우 빌드에 성공했습니다.


일단, Ubuntu 14.04 를 설치한 황을 가정하고 설명을 시작하겠습니다. 이유는 제가 빌드에 성공한 버전이기도 하지만, 그나마 예외적인 사항들이 적은 편이기 때문입니다.


https://source.android.com/setup/build/requirements 를 보면 먼저 간단한 요구사항들이 있습니다.


JDK

See Installing the JDK for the prebuilt path and installation instructions for older versions.



그 중 가장 중요한 것은 어떤 버전을 빌드할 것인가 입니다. 이를 테면, Lollipop 을 빌드한다고 하면,  Java 1.7 이 필요합니다. 최신의 Nougat 이상을 빌드하고 싶다면, 현재 보통 사용하고 있는 1.8 을 그냥 사용 하면 되겠지만, 그 이전 버전일 경우에는 위 표를 반드시 알고 미리 준비해두어야 합니다. 만약, JAVA 버전이 다를 경우, 빌드시 에러가 발생합니다.



이후에는 https://source.android.com/setup/build/initializing 에 따라 14.04 에 해당하는 명령을 실행해주면 됩니다. 위 그림에서 '클릭하여 복사' 하여 실행하셔도 됩니다. 



이젠 소스를 다운로드 받아야 합니다. https://source.android.com/setup/build/downloading 에 따라 소스를 받으면 되는데, repo 설정과 그외 부분은 위 그림에서와 같이 '클릭하여 복사'를 잘 이용하시면 편리합니다. 가장 중요한 것은 어떤 브랜치를 가져올것인가 입니다. 

아래 그림에서 'repo init - u https://android.googesource.com/platform/manifest -b android-4.0.1_r1' 에서 android-4.0.1_r1 에 해당하는 부분인데요.

푸른 색 글씨의 Source Code Tags and Builds 링크를 따라가서 무엇을 받을지를 결정하셔야 합니다.




저는 Nexus6P 를 빌드해야 했기 때문에 Nexus6P 를 검색해서 실제 Factory Image 가 올라와있는 버전(MDB08K)을 선택했습니다.




https://developers.google.com/android/images 에서 미리 자신이 가지고 있는 단말의 Factory Image 를 미리 받아서 언제든 원복 시킬수 있거나 소스코드를 수정했을 때, 본래 이미지와 비교할 수 있는 버전을 받아 놓는게 좋습니다. 팩토리 이미지를 설치하는 방법은 다음 글에서 설명해드릴게요.



그래서 저는 'repo init - u https://android.googesource.com/platform/manifest -b android-6.0.0_r24' 로 다운로드를 받았습니다.

그리고, 페이지의 설명대로 'repo sync' 를 시작하면 다운로드를 시작합니다.

주의하실 점은 소스 자체의 크기는 그렇게 크다고 볼 수 없지만, 요즘은 git 정보가 너무 많아서 다운로드에만 50G 이상이 사용됩니다. 빌드할 때 여유공간까지 생각하면 150G 정도의 충분한 여유공간을 만들어 놓는 것이 좋습니다. 

물론, 정보를 적게 가져오는 방법이 있기는 하지만, 여기서는 일단 스킵하고 최대한 많은 여유공간을 확보해두시는 걸 권장해드리고 싶습니다.

그리고, 다운로드 받는데도 꽤 오랜 시간이 걸립니다. 족히 한시간은 걸렸던 걸로 기억이되네요.


다운로드를 받고나서 빌드를 하는 과정은 오히려 어렵지 않습니다. https://source.android.com/setup/build/building 에 나온 대로 'make clobber' -> 'source build/envsetup.sh' -> 'lunch' -> 'make -j4' 순서로 실행해 주시면 됩니다.



사이트에서는 'lunch aosp_arm-eng' 를 예로 들었는데, 'lunch' 만 실행해 보시면 아래와 같이 옵션이 많이 있다는걸 알게됩니다.



저는 Nexus6P 의 코드네임 angler 를 따라 17번  aosp_angler-userdebug 를 선택해서 빌드했습니다.



BUILD_ID=MDB08K 를 보내 뭔가 제대로 된 느낌입니다. ^^; 

'make -j4' 로 빌드를 시작하면 됩니다. 빌드 환경에 따라 -j2 혹은 -j8 로 시작하셔도 됩니다. 숫자가 클수록 빨리 끝나기는 합니다. 그래도 최소 한시간정도는 기다려야 합니다.

빌드가 성공적으로 끝나면 /WORKING_DIRECTORY/out/target/product/[target_code_name] 에 이미지가 생성됩니다.

저는 Nexus6P 이기 때문에 angler 디렉토리에 생성되어 있습니다.



이렇게 빌드된 이미지 파일들을 단말에 설치하면 됩니다. 설치 방법은 다음글에서 안내해 드릴게요.

Compile 은 안드로이드 상위 버전(예: sdkVersion=19)으로 한 뒤, 하위 버전(예: sdkVersion=8)에서 실행할 때 아래와 같은 에러를 만나게 되는 경우에는 Library Project 혹은 Library 의 문제가 아니라, 프로젝트에서 사용하고 있는 
"?android:attr/" 의 문제이다. 
상위 버전의 attr 을 resource id 를 사용하는 것이기 때문에 하위버전에서는 엉뚱한 리소스를 찾다가 실패하는 것이다. 

 Caused by: android.content.res.Resources$NotFoundException: Resource is not a Drawable (color or path): TypedValue{t=0x2/d=0x10102fd a=-1} 
혹은 
 java.io.FileNotFoundException: res/drawable-hdpi/divider_horizontal_bright_opaque.9.png

와 같은 에러를 만나게 된다.


프로젝트 xml 파일에서 "?android:attr/" 로 검색하여 최신 속성을 사용하고 있는 것인지 확인해야 한다.


p.s. 본디, 이런 포스팅은 하지 않는데,.. 너무 어이없이 삽질을 하다보니 일단 기록을 남겨둔다.

  1. Denial 2014.08.09 07:01 신고

    저두 정말 어처구니 없는 삽질을 했었네요 ㅠ 눈치챌 즈음에 여기를 발견했습니다. ㅎㅎ

시작하기에 앞서 아래 사이트를 참조하면 좋다.

http://android-developers.blogspot.kr/2013/10/getting-your-sms-apps-ready-for-kitkat.html (영문) 

http://android-developers-kr.blogspot.kr/2013/10/blog-post_15.html (국문 번역)


위 사이트를 참조하면 기본 SMS 앱으로 설정되려면, 아래와 같이 두 개의 BroadcastReciever(SMS_DELIVER 와 WAP_PUSH_DELIVER action 을 받을 수 있는)와 sms, smsto, mms, mmsto scheme 을 받아줄 수 있는 Activity, 그리고, RESPOND_VIA_MESSAGE action 을 받을 수 있는 Service 가 구현되어 있어야 한다.


<manifest>
    ...
    <application>
        <!-- BroadcastReceiver that listens for incoming SMS messages -->
        <receiver android:name=".SmsReceiver"
                android:permission="android.permission.BROADCAST_SMS">
            <intent-filter>
                <action android:name="android.provider.Telephony.SMS_DELIVER" />
            </intent-filter>
        </receiver>

        <!-- BroadcastReceiver that listens for incoming MMS messages -->
        <receiver android:name=".MmsReceiver"
            android:permission="android.permission.BROADCAST_WAP_PUSH">
            <intent-filter>
                <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
                <data android:mimeType="application/vnd.wap.mms-message" />
            </intent-filter>
        </receiver>

        <!-- Activity that allows the user to send new SMS/MMS messages -->
        <activity android:name=".ComposeSmsActivity" >
            <intent-filter>
                <action android:name="android.intent.action.SEND" />                
                <action android:name="android.intent.action.SENDTO" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="sms" />
                <data android:scheme="smsto" />
                <data android:scheme="mms" />
                <data android:scheme="mmsto" />
            </intent-filter>
        </activity>

        <!-- Service that delivers messages from the phone "quick response" -->
        <service android:name=".HeadlessSmsSendService"
                 android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
                 android:exported="true" >
            <intent-filter>
                <action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="sms" />
                <data android:scheme="smsto" />
                <data android:scheme="mms" />
                <data android:scheme="mmsto" />
            </intent-filter>
        </service>
    </application>
</manifest>


+ Recent posts