1 #!/bin/bash 2 # 3 # This script builds the AOSP Android jars, and installs them in your local 4 # Maven repository. See: http://source.android.com/source/building.html for 5 # more information on building AOSP. 6 # 7 # Usage: 8 # build-android.sh <android repo path> <android version> <robolectric version> 9 # 10 # For a tutorial check scripts/README.md 11 12 set -ex 13 14 function usage() { 15 echo "Usage: ${0} <android repo path> <android-version> <robolectric-sub-version> <output directory>" 16 } 17 18 if [[ $# -ne 4 ]]; then 19 usage 20 exit 1 21 fi 22 23 buildRoot=$1 24 25 if [[ ! -d $buildRoot ]]; then 26 echo $buildRoot is not a directory 27 usage 28 exit 1 29 fi 30 31 if [[ -z "${SIGNING_PASSWORD}" ]]; then 32 echo "Please set the GPG passphrase as SIGNING_PASSWORD" 33 exit 1 34 fi 35 36 buildRoot=$(cd $buildRoot; pwd) 37 38 ANDROID_VERSION=$2 39 ROBOLECTRIC_SUB_VERSION=$3 40 41 SCRIPT_DIR=$(cd $(dirname "$0"); pwd) 42 43 ANDROID_SOURCES_BASE=${buildRoot} 44 FRAMEWORKS_BASE_DIR=${ANDROID_SOURCES_BASE}/frameworks/base 45 FRAMEWORKS_RAW_RES_DIR=${FRAMEWORKS_BASE_DIR}/core/res/ 46 ROBOLECTRIC_VERSION=${ANDROID_VERSION}-robolectric-${ROBOLECTRIC_SUB_VERSION} 47 48 # Intermediate artifacts 49 ANDROID_RES=android-res-${ANDROID_VERSION}.jar 50 ANDROID_EXT=android-ext-${ANDROID_VERSION}.jar 51 ANDROID_CLASSES=android-classes-${ANDROID_VERSION}.jar 52 53 # API specific paths 54 LIB_PHONE_NUMBERS_PKG="com/android/i18n/phonenumbers" 55 LIB_PHONE_NUMBERS_PATH="external/libphonenumber/java/src" 56 57 # Final artifact names 58 ANDROID_ALL=android-all-${ROBOLECTRIC_VERSION}.jar 59 ANDROID_ALL_POM=android-all-${ROBOLECTRIC_VERSION}.pom 60 ANDROID_ALL_SRC=android-all-${ROBOLECTRIC_VERSION}-sources.jar 61 ANDROID_ALL_DOC=android-all-${ROBOLECTRIC_VERSION}-javadoc.jar 62 ANDROID_BUNDLE=android-all-${ROBOLECTRIC_VERSION}-bundle.jar 63 64 TZDATA_ARCH="generic_x86" 65 66 build_platform() { 67 NATIVE_ARTIFACTS=() 68 69 if [[ "${ANDROID_VERSION}" == "4.1.2_r1" ]]; then 70 ARTIFACTS=("core" "services" "framework" "android.policy" "ext") 71 SOURCES=(core/java graphics/java media/java location/java opengl/java policy/src sax/java services/java telephony/java wifi/java) 72 elif [[ "${ANDROID_VERSION}" == "4.2.2_r1.2" ]]; then 73 ARTIFACTS=("core" "services" "telephony-common" "framework" "android.policy" "ext") 74 SOURCES=(core/java graphics/java media/java location/java opengl/java policy/src sax/java services/java telephony/java wifi/java) 75 elif [[ "${ANDROID_VERSION}" == "4.3_r2" ]]; then 76 ARTIFACTS=("core" "services" "telephony-common" "framework" "android.policy" "ext") 77 SOURCES=(core/java graphics/java media/java location/java opengl/java policy/src sax/java services/java telephony/java wifi/java) 78 elif [[ "${ANDROID_VERSION}" == "4.4_r1" ]]; then 79 ARTIFACTS=("core" "services" "telephony-common" "framework" "framework2" "framework-base" "android.policy" "ext" "webviewchromium" "okhttp" "conscrypt") 80 SOURCES=(core/java graphics/java media/java location/java opengl/java policy/src sax/java services/java telephony/java wifi/java) 81 elif [[ "${ANDROID_VERSION}" == "5.0.2_r3" ]]; then 82 ARTIFACTS=("core-libart" "services" "telephony-common" "framework" "android.policy" "ext" "okhttp" "conscrypt") 83 SOURCES=(core/java graphics/java media/java location/java opengl/java policy/src sax/java services/java telephony/java wifi/java) 84 TZDATA_ARCH="generic" 85 elif [[ "${ANDROID_VERSION}" == "5.1.1_r9" ]]; then 86 ARTIFACTS=("core-libart" "services" "telephony-common" "framework" "android.policy" "ext" "okhttp" "conscrypt") 87 SOURCES=(core/java graphics/java media/java location/java opengl/java policy/src sax/java services/java telephony/java wifi/java) 88 TZDATA_ARCH="generic" 89 elif [[ "${ANDROID_VERSION}" == "6.0.1_r3" ]]; then 90 ARTIFACTS=("core-libart" "services" "services.accessibility" "telephony-common" "framework" "ext" "icu4j-icudata-jarjar" "okhttp" "conscrypt") 91 SOURCES=(core/java graphics/java media/java location/java opengl/java sax/java services/java telephony/java wifi/java) 92 LIB_PHONE_NUMBERS_PKG="com/google/i18n/phonenumbers" 93 LIB_PHONE_NUMBERS_PATH="external/libphonenumber/libphonenumber/src" 94 TZDATA_ARCH="generic" 95 elif [[ "${ANDROID_VERSION}" == "7.0.0_r1" ]]; then 96 ARTIFACTS=("core-libart" "services" "services.accessibility" "telephony-common" "framework" "ext" "okhttp" "conscrypt") 97 NATIVE_ARTIFACTS=("icu4j-icudata-host-jarjar" "icu4j-icutzdata-host-jarjar") 98 SOURCES=(core/java graphics/java media/java location/java opengl/java sax/java services/java telephony/java wifi/java) 99 LIB_PHONE_NUMBERS_PKG="com/google/i18n/phonenumbers" 100 LIB_PHONE_NUMBERS_PATH="external/libphonenumber/libphonenumber/src" 101 elif [[ "${ANDROID_VERSION}" == "7.1.0_r7" ]]; then 102 ARTIFACTS=("core-libart" "services" "services.accessibility" "telephony-common" "framework" "ext" "okhttp" "conscrypt") 103 NATIVE_ARTIFACTS=("icu4j-icudata-host-jarjar" "icu4j-icutzdata-host-jarjar") 104 SOURCES=(core/java graphics/java media/java location/java opengl/java sax/java services/java telephony/java wifi/java) 105 LIB_PHONE_NUMBERS_PKG="com/google/i18n/phonenumbers" 106 LIB_PHONE_NUMBERS_PATH="external/libphonenumber/libphonenumber/src" 107 elif [[ "${ANDROID_VERSION}" == "8.0.0_r4" ]]; then 108 ARTIFACTS=("robolectric_android-all") 109 NATIVE_ARTIFACTS=() 110 SOURCES=(core/java graphics/java media/java location/java opengl/java sax/java services/java telephony/java wifi/java) 111 else 112 echo "Robolectric: No match for version: ${ANDROID_VERSION}" 113 exit 1 114 fi 115 116 cd ${ANDROID_SOURCES_BASE} 117 if [ ! -d out/target/common/obj/JAVA_LIBRARIES ]; then 118 echo "Robolectric: You need to run 'sync-android.sh' first" 119 exit 1 120 fi 121 } 122 123 build_android_res() { 124 echo "Robolectric: Building android-res..." 125 cd ${FRAMEWORKS_BASE_DIR}/core/res; jar cf ${OUT}/${ANDROID_RES} . 126 src=${ANDROID_SOURCES_BASE}/out/target/common/obj/APPS/framework-res_intermediates/package-export.apk 127 cp $src ${OUT}/${ANDROID_RES} 128 } 129 130 build_android_ext() { 131 echo "Robolectric: Building android-ext..." 132 mkdir -p ${OUT}/ext-classes-modified/${LIB_PHONE_NUMBERS_PKG} 133 cd ${OUT}/ext-classes-modified; jar xf ${ANDROID_SOURCES_BASE}/out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/classes.jar 134 cp -R ${ANDROID_SOURCES_BASE}/${LIB_PHONE_NUMBERS_PATH}/${LIB_PHONE_NUMBERS_PKG}/data ${OUT}/ext-classes-modified/${LIB_PHONE_NUMBERS_PKG} 135 cd ${OUT}/ext-classes-modified; jar cf ${OUT}/${ANDROID_EXT} . 136 rm -rf ${OUT}/ext-classes-modified 137 } 138 139 build_android_classes() { 140 echo "Robolectric: Building android-classes..." 141 mkdir ${OUT}/android-all-classes 142 for artifact in "${ARTIFACTS[@]}"; do 143 src=${ANDROID_SOURCES_BASE}/out/target/common/obj/JAVA_LIBRARIES/${artifact}_intermediates 144 cd ${OUT}/android-all-classes 145 if [[ -f ${src}/classes.jar ]]; then 146 jar xf ${src}/classes.jar 147 else 148 echo "Couldn't find ${artifact} at ${src}/classes.jar" 149 exit 1 150 fi 151 done 152 153 for artifact in "${NATIVE_ARTIFACTS[@]}"; do 154 jarPath=${ANDROID_SOURCES_BASE}/out/host/linux-x86/framework/${artifact}.jar 155 cd ${OUT}/android-all-classes 156 if [[ -f $jarPath ]]; then 157 jar xf $jarPath 158 else 159 echo "Couldn't find ${artifact} at $jarPath" 160 exit 1 161 fi 162 done 163 build_tzdata 164 build_prop 165 cd ${OUT}/android-all-classes; jar cf ${OUT}/${ANDROID_CLASSES} . 166 rm -rf ${OUT}/android-all-classes 167 } 168 169 build_tzdata() { 170 echo "Robolectric: Building tzdata..." 171 mkdir -p ${OUT}/android-all-classes/usr/share/zoneinfo 172 cp ${ANDROID_SOURCES_BASE}/out/target/product/${TZDATA_ARCH}/system/usr/share/zoneinfo/tzdata ${OUT}/android-all-classes/usr/share/zoneinfo 173 } 174 175 build_prop() { 176 cp ${ANDROID_SOURCES_BASE}/out/target/product/generic_x86/system/build.prop ${OUT}/android-all-classes 177 } 178 179 build_android_all_jar() { 180 echo "Robolectric: Building android-all..." 181 mkdir ${OUT}/android-all 182 cd ${OUT}/android-all; unzip ${OUT}/${ANDROID_RES} 183 # temporarily add raw resources too 184 cd ${OUT}/android-all; rsync -a ${FRAMEWORKS_RAW_RES_DIR} raw-res 185 cd ${OUT}/android-all; jar xf ${OUT}/${ANDROID_EXT} 186 cd ${OUT}/android-all; jar xf ${OUT}/${ANDROID_CLASSES} 187 188 # Remove unused files 189 rm -rf ${OUT}/android-all/Android.mk 190 rm -rf ${OUT}/android-all/raw-res/Android.mk 191 rm -rf ${OUT}/android-all/AndroidManifest.xml 192 rm -rf ${OUT}/android-all/raw-resAndroidManifest.xml 193 rm -rf ${OUT}/android-all/META-INF 194 rm -rf ${OUT}/android-all/MODULE_LICENSE_APACHE2 195 rm -rf ${OUT}/android-all/raw-res/MODULE_LICENSE_APACHE2 196 rm -rf ${OUT}/android-all/MakeJavaSymbols.sed 197 rm -rf ${OUT}/android-all/raw-res/MakeJavaSymbols.sed 198 rm -rf ${OUT}/android-all/NOTICE 199 rm -rf ${OUT}/android-all/raw-res/NOTICE 200 rm -rf ${OUT}/android-all/lint.xml 201 rm -rf ${OUT}/android-all/raw-res/lint.xml 202 rm -rf ${OUT}/android-all/java/lang 203 204 # Build the new JAR file 205 cd ${OUT}/android-all; jar cf ${OUT}/${ANDROID_ALL} . 206 rm ${OUT}/${ANDROID_RES} ${OUT}/${ANDROID_EXT} ${OUT}/${ANDROID_CLASSES} 207 } 208 209 cp_android_all_jar() { 210 # function to use for android versions that support building the android all 211 # jar directly 212 # This will just copy the android all jar to the final name 213 src=${ANDROID_SOURCES_BASE}/out/target/common/obj/JAVA_LIBRARIES/robolectric_android-all-stub_intermediates/classes-with-res.jar 214 cp $src ${OUT}/${ANDROID_ALL} 215 } 216 217 build_android_src_jar() { 218 echo "Robolectric: Building android-all-source..." 219 local src=${ANDROID_SOURCES_BASE}/frameworks/base 220 local tmp=${OUT}/sources 221 mkdir ${tmp} 222 223 for sourceSubDir in "${SOURCES[@]}"; do 224 rsync -a ${src}/${sourceSubDir}/ ${tmp}/ 225 done 226 rsync -a ${ANDROID_SOURCES_BASE}/libcore/luni/src/main/java/ ${tmp}/ # this is new 227 cd ${tmp}; jar cf ${OUT}/${ANDROID_ALL_SRC} . 228 rm -rf ${tmp} 229 } 230 231 build_android_doc_jar() { 232 # TODO: Actually build the docs 233 echo "Robolectric: Building android-all-javadoc..." 234 mkdir ${OUT}/javadoc 235 cd ${OUT}/javadoc; jar cf ${OUT}/${ANDROID_ALL_DOC} . 236 rm -rf ${OUT}/javadoc 237 } 238 239 build_signed_packages() { 240 echo "Robolectric: Building android-all.pom..." 241 sed s/VERSION/${ROBOLECTRIC_VERSION}/ ${SCRIPT_DIR}/pom_template.xml | sed s/ARTIFACT_ID/android-all/ > ${OUT}/${ANDROID_ALL_POM} 242 243 echo "Robolectric: Signing files with gpg..." 244 for ext in ".jar" "-javadoc.jar" "-sources.jar" ".pom"; do 245 ( cd ${OUT} && gpg -ab --passphrase ${SIGNING_PASSWORD} android-all-${ROBOLECTRIC_VERSION}$ext ) 246 done 247 248 echo "Robolectric: Creating bundle for Sonatype upload..." 249 cd ${OUT}; jar cf ${ANDROID_BUNDLE} *.jar *.pom *.asc 250 } 251 252 mavenize() { 253 local FILE_NAME_BASE=android-all-${ROBOLECTRIC_VERSION} 254 mvn install:install-file \ 255 -Dfile=${OUT}/${FILE_NAME_BASE}.jar \ 256 -DgroupId=org.robolectric \ 257 -DartifactId=android-all \ 258 -Dversion=${ROBOLECTRIC_VERSION} \ 259 -Dpackaging=jar 260 261 mvn install:install-file \ 262 -Dfile=${OUT}/${FILE_NAME_BASE}-sources.jar \ 263 -DgroupId=org.robolectric \ 264 -DartifactId=android-all \ 265 -Dversion=${ROBOLECTRIC_VERSION} \ 266 -Dpackaging=jar \ 267 -Dclassifier=sources 268 269 mvn install:install-file \ 270 -Dfile=${OUT}/${FILE_NAME_BASE}-javadoc.jar \ 271 -DgroupId=org.robolectric \ 272 -DartifactId=android-all \ 273 -Dversion=${ROBOLECTRIC_VERSION} \ 274 -Dpackaging=jar \ 275 -Dclassifier=javadoc 276 } 277 278 if [[ ! -d "${4}" ]]; then 279 echo "$4 is not a directory" 280 exit 1 281 fi 282 283 OUT=${4}/${ANDROID_VERSION} 284 mkdir -p ${OUT} 285 286 build_platform 287 if [[ "${ANDROID_VERSION}" == "8.0.0_r4" ]]; then 288 cp_android_all_jar 289 else 290 build_android_res 291 build_android_ext 292 build_android_classes 293 build_android_all_jar 294 fi 295 296 build_android_src_jar 297 build_android_doc_jar 298 build_signed_packages 299 mavenize 300 301 echo "DONE!!" 302 echo "Your artifacts are located here: ${OUT}" 303