1# ICU version upgrade 2 3Upgrade the ICU on Android to the new upstream version. The new upstream versions can be found at 4https://github.com/unicode-org/icu/releases. 5 6The below contains the steps and commands in order to upgrade the ICU version in the AOSP. 7 8# Prerequisites 91. Install the prerequisite tools 10 * See http://site.icu-project.org/repository 11 * [git-lts](https://git-lfs.github.com/) has to be installed to pull binaries correctly from the github. 12 * [git-filter-repo](https://github.com/newren/git-filter-repo) for rewriting the `Change-Id` later. 132. Generate a github read-access token and setup a local ~/.m2/setting.xml 14 * See http://cldr.unicode.org/development/maven. This is required to download 15 the prebuilt ICU to break the circular dependency between CLDR and icu. 163. Check out aosp/main 17 * http://go/repo-init/aosp-main-with-phones 18 19# Branch Structure 201. `external/icu` project in the AOSP, 21 * We **rebase** Android-specific patches on the `icu-staging` branch. Then we merge into 22 `aosp/main` later. 232. `external/cldr` project 24 * We use the **`aosp/upstream-release-cldr** as the mirror of the upstream release branch. 25 We don’t modify this branch with Android patches, but merge this branch 26 into aosp/main where the Android patches are located. 27 28# Verifying the cleanliness 291. Build the clean source of AOSP 30 ```shell 31 source build/envsetup.sh 32 lunch aosp_cf_x86_64_phone-trunk_staging-userdebug 33 m 34 ``` 35 The build should succeed. Otherwise, your local repo may be broken. Please consider to re-sync. 362. Verify that the generated artifacts are clean 37 * If you re-run the generation scripts and it causes new changes, some patches are missing 38 in the sources, e.g. `icu4j/` and `icu4c` or `external/cldr`. 39 * The scripts include 40 ```shell 41 external/icu/tools/updatecldrdata.py 42 external/icu/tools/updateicudata.py 43 system/timezone/update-tzdata.py 44 external/icu/tools/srcgen/generate_android_icu4j.sh 45 external/icu/tools/icu4c_srcgen/generate_libandroidicu.py 46 external/icu/tools/icu4c_srcgen/generate_ndk.py 47 ``` 48 49# Steps 501. Configure the versions and temp directory 51 52 * Customize the following environment variables. 53 The following example targets the ICU 76.1 and CLDR 46.0 version. 54 ```shell 55 export ICU_VERSION=76 56 export ICU_MINOR_VERSION=1 57 export CLDR_VERSION=46 58 export ICU_UPGRADE_BUG=1234567890 # buganizer bug 59 # Initially empty directory to store upstream source 60 export UPSTREAM_CLDR_GIT=/media/user/disk/icu-git/cldr 61 export UPSTREAM_ICU_GIT=/media/user/disk/icu-git/icu 62 ``` 63 642. Copy the CLDR sources into the `upstream-release-cldr` branch 65 66 2a. Copy sources 67 ```shell 68 export CLDR_UPSTREAM_BRANCH=release-${CLDR_VERSION} 69 70 cd ${ANDROID_BUILD_TOP}/external/cldr 71 git fetch aosp upstream-release-cldr 72 git branch ${CLDR_UPSTREAM_BRANCH} --track aosp/upstream-release-cldr 73 git checkout ${CLDR_UPSTREAM_BRANCH} 74 75 git clone https://github.com/unicode-org/cldr.git ${UPSTREAM_CLDR_GIT} 76 77 git --git-dir=${UPSTREAM_CLDR_GIT}/.git --work-tree=${UPSTREAM_CLDR_GIT} fetch 78 git --git-dir=${UPSTREAM_CLDR_GIT}/.git --work-tree=${UPSTREAM_CLDR_GIT} checkout ${CLDR_UPSTREAM_BRANCH} 79 rm -rf * 80 cp -r ${UPSTREAM_CLDR_GIT}/* . 81 git clean -dfX # Remove ignored files 82 git add -A 83 git commit -F- <<EOF 84 Copy upstream ${CLDR_UPSTREAM_BRANCH} 85 86 Bug: ${ICU_UPGRADE_BUG} 87 Test: n/a 88 EOF 89 # Upload this CL to upstream-release-cldr branch 90 repo upload --cbr . 91 ``` 92 93 2b. Merge the upstream sources with patches in `aosp/main` 94 ```shell 95 export CLDR_BRANCH=cldr${CLDR_VERSION}-main 96 git branch ${CLDR_BRANCH} --track aosp/main 97 git checkout ${CLDR_BRANCH} 98 git merge ${CLDR_UPSTREAM_BRANCH} -m " 99 Merge CLDR ${CLDR_VERSION} in upstream-release-cldr into aosp/main 100 101 Bug: ${ICU_UPGRADE_BUG} 102 Test: external/icu/tools/updatecldrdata.py 103 " 104 ``` 105 106 2c. Resolve any merge conflicts with the Android-specific patches. 107 Continue creating the merge commit 108 ```shell 109 git merge --continue 110 ``` 111 112 2d. Upload the CL to main branch 113 ```shell 114 repo upload --cbr . 115 ``` 116 1173. Copy ICU upstream sources into external/icu 118 ```shell 119 cd ${ANDROID_BUILD_TOP}/external/icu 120 export ICU_BRANCH=icu-staging 121 export UPSTREAM_RELEASE_TAG=release-${ICU_VERSION}-${ICU_MINOR_VERSION} 122 git fetch aosp main ${ICU_BRANCH} 123 git branch ${ICU_BRANCH} --track aosp/${ICU_BRANCH} 124 git checkout ${ICU_BRANCH} 125 # Merge main into the staging branch. 126 git merge --no-ff aosp/main -m 127 " 128 Merge branch aosp/main into ${ICU_BRANCH} 129 130 Bug: ${ICU_UPGRADE_BUG} 131 Test: n/a 132 " 133 # Clone the upstream CLDR repo locally to ${UPSTREAM_ICU_GIT} 134 test -d ${UPSTREAM_ICU_GIT} || git clone https://github.com/unicode-org/icu.git ${UPSTREAM_ICU_GIT} 135 136 git --git-dir=${UPSTREAM_ICU_GIT}/.git --work-tree=${UPSTREAM_ICU_GIT} fetch 137 git --git-dir=${UPSTREAM_ICU_GIT}/.git --work-tree=${UPSTREAM_ICU_GIT} checkout ${UPSTREAM_RELEASE_TAG} 138 find icu4j/ -type f,d ! -regex ".*/\(Android.mk\|Android.bp\|adjust_icudt_path.mk\|liblayout-jarjar-rules.txt\|.gitignore\|AndroidTest.xml\)" -delete 139 find icu4c/ -type f,d ! -regex ".*/\(Android.mk\|Android.bp\|.gitignore\|AndroidTest.xml\)" -delete 140 cp -r ${UPSTREAM_ICU_GIT}/icu4j . 141 cp -r ${UPSTREAM_ICU_GIT}/icu4c . 142 git checkout HEAD -- icu4c/.gitignore icu4j/.gitignore # Android has extra .gitignores. Use our version. 143 rm -r tools/cldr 144 cp -r ${UPSTREAM_ICU_GIT}/tools/cldr tools/cldr 145 146 git add -A 147 git commit -F- <<EOF 148 Copy ICU ${UPSTREAM_RELEASE_TAG} into aosp/${ICU_BRANCH} 149 150 Copy the files with the following commands: 151 find icu4j/ -type f,d ! -regex ".*/\(Android.mk\|Android.bp\|adjust_icudt_path.mk\|liblayout-jarjar-rules.txt\|.gitignore\|AndroidTest.xml\)" -delete 152 find icu4c/ -type f,d ! -regex ".*/\(Android.mk\|Android.bp\|.gitignore\|AndroidTest.xml\)" -delete 153 cp -r \${UPSTREAM_ICU_GIT}/icu4j . 154 cp -r \${UPSTREAM_ICU_GIT}/icu4c . 155 git checkout HEAD -- icu4c/.gitignore icu4j/.gitignore 156 rm -r tools/cldr 157 cp -r \${UPSTREAM_ICU_GIT}/tools/cldr tools/cldr 158 EOF 159 ``` 160 1614. Apply Android-specific patches into `external/icu` 162 163 4a. Cherry-pick the patches from the last staging branch. For example using the following query for ICU 71 patches 164 * https://android-review.git.corp.google.com/q/%22Android+patch%22+branch:icu-staging+status:merged 165 * The cherry-pick command is 166 ```shell 167 git cherry-pick <first_patch_in_the_chain>~1..<last_patch_in_the_chain> 168 ``` 169 4b. Cherry-pick the patches since the ICU upgrade 170 * Find the patches with this query. 171 https://r.android.com/q/%2522Android+patch%2522+project:platform/external/icu+status:merged+-owner:automerger+-owner:android-build-coastguard-worker%2540google.com+branch:main 172 4c. Reset `Change-Id` in the cherry-picked CLs 173 * ```shell 174 THE_COPY_COMMIT=$(git log --pretty=format:'%h' -n 1 --grep "Copy ICU ${UPSTREAM_RELEASE_TAG} into aosp/${ICU_BRANCH}") 175 git filter-branch -f --msg-filter 'sed "s/Change-Id: .*//g"' ${THE_COPY_COMMIT}..HEAD 176 git rebase -i ${THE_COPY_COMMIT} # It should open vim 177 # Replace pick with reword in vim `%s/pick /reword /g` 178 # Close all commit message edits with :wq in vim 179 # It triggers the git-hook to generate a Change-Id. 180 # TODO: Find a better way to generate Change-Id 181 ``` 1825. Regenerate and commit the artifacts 183 184 5a. Update icu source data files 185 ```shell 186 croot external/icu 187 tools/updatecldrdata.py 188 189 git add -A 190 git commit -F- <<EOF 191 Regenerated source data files with Android CLDR patches 192 193 Source data files updated using: 194 tools/updatecldrdata.py 195 196 Test: n/a 197 EOF 198 ``` 199 200 5b. Update icu binary data files 201 ```shell 202 tools/updateicudata.py 203 git add -A 204 git commit -F- <<EOF 205 Regenerated binary data files with Android CLDR patches 206 207 Binary data files updated using: 208 tools/updateicudata.py 209 210 Test: n/a 211 EOF 212 ``` 213 214 5c. Pin the public API surface temporarily 215 * We will later expose the new APIs after submitting the version upgrade CLs. 216 ```shell 217 ./tools/srcgen/generate_allowlisted_public_api.sh 218 git add -A 219 git commit -F- <<EOF 220 Pin the current API list 221 222 Test: ./tools/srcgen/generate_allowlisted_public_api.sh 223 EOF 224 ``` 225 226 5d. Regenerate android_icu4j/ 227 * Commands 228 ```shell 229 tools/srcgen/generate_android_icu4j.sh 230 231 git add -A 232 git commit -F- <<EOF 233 Regenerate android_icu4j/ from icu4j/ 234 235 android_icu4j files updated using: 236 tools/srcgen/generate_android_icu4j.sh 237 238 Test: n/a 239 EOF 240 ``` 241 * If any java patches are not applied perfectly, remove the .orig and 242 .rej files with the following command 243 ```shell 244 find android_icu4j/ -name *.orig -delete 245 # Please manually update and resolve conflict of the java doc in android_icu4j/ 246 git commit -amend 247 # Regenerate the patch files 248 ./tools/srcgen/javadoc_patches/create_patches.sh 249 git add -A && git commit -F- <<EOF 250 Regenerate java doc patches 251 252 Test: n/a 253 EOF 254 ``` 255 256 5e. Re-genereate libandroidicu/ sources 257 ```shell 258 ./tools/icu4c_srcgen/generate_libandroidicu.py 259 git add -A && git commit -F- <<EOF 260 Regenerate libandroidicu 261 262 The command: 263 ./tools/icu4c_srcgen/generate_libandroidicu.py 264 265 Test: n/a 266 EOF 267 ``` 268 269 5f. Regenerate libicu/ sources 270 * Commands 271 ```shell 272 ./tools/icu4c_srcgen/generate_ndk.py 273 274 git add -A && git commit -a -F- <<EOF 275 Regenerate libicu.so and ICU4C CTS headers 276 277 The command: 278 ./tools/icu4c_srcgen/generate_ndk.py 279 280 Test: n/a 281 EOF 282 ``` 283 * Review the changes in libicu/ndk_headers/unicode. Check that 284 no ABI change is in the C struct or API signature. 285 ```shell 286 git diff HEAD~1 ./libicu/ndk_headers/ 287 ``` 288 * May need to run this to update .patch files 289 ```shell 290 # Manually update doxygen doc in the .h headers in libicu/ndk_headers 291 ./tools/icu4c_srcgen/doc_patches/create_patches.sh 292 git add -A && git commit -F- <<EOF 293 Regenerate patches in libicu headers 294 EOF 295 ``` 296 297 5g. [Not required for every ICU release] Increment Distro major version 298 * See https://android.googlesource.com/platform/system/timezone/+/main/README.android 299 for details. Usually, it’s needed only when it’s the first ICU upgrade 300 in the Android dessert release. 301 302 5h. Generate time zone files 303 ```shell 304 cd $ANDROID_BUILD_TOP/system/timezone 305 repo start ${ICU_BRANCH} . 306 ./update-tzdata.py 307 git add -A 308 git commit -F- <<EOF 309 Regenerate data files for ICU ${ICU_VERSION} upgrade 310 311 Binary data files updated using: 312 system/timezone/update-tzdata.py 313 314 This updates the ICU version number inside of icu_tzdata.dat but doesn't 315 change the timezone data itself. 316 317 Bug: ${ICU_UPGRADE_BUG} 318 Test: n/a 319 EOF 320 321 # If only the build time in icu4c/source/data/misc/zoneinfo64.txt, this step isn't needed. 322 cd $ANDROID_BUILD_TOP/external/icu 323 git add -A 324 git commit -F- <<EOF 325 Regenerate tz-related data files 326 327 Data files updated using: 328 system/timezone/update-tzdata.py 329 330 Bug: ${ICU_UPGRADE_BUG} 331 Test: n/a 332 EOF 333 ``` 334 335 * Ideally, it should not generate new time zone data files if tzdata has been updated for a new 336 tzdb release 337 * If it updates time zone data, there could be extra changes from CLDR. Talk to 338 android-libcore-team@ how to deal with the updates, because they may need to cherry-pick 339 them into tzdata module updates. 340 341 5i. Update the version numbers in the METADATA 342 1. Update the external/icu/README.version 343 2. Update version and upgrade date in external/cldr/METADATA 344 3. `git commit` the file change 345 346 5j. Regenerate frameworks/base/libs/androidfw/LocaleDataTables.cpp 347 ```shell 348 croot frameworks/base 349 ./tools/localedata/extract_icu_data.py $ANDROID_BUILD_TOP > libs/androidfw/LocaleDataTables.cpp 350 git commit -a -F- <<EOF 351 Regenerate LocaleDataTables.cpp due to ICU ${ICU_VERSION} upgrade 352 353 The command: 354 ./tools/localedata/extract_icu_data.py \$ANDROID_BUILD_TOP > libs/androidfw/LocaleDataTables.cpp 355 356 Bug: ${ICU_UPGRADE_BUG} 357 Test: atest FrameworksCoreTests:android.text.format 358 EOF 359 ``` 3606. Build and run test 361 362 6a. Build by `m droid cts` 363 364 6b. Run the device tests by `atest CtsIcu4cTestCases CtsIcuTestCases CtsLibcoreTestCases CtsLibcoreOjTestCases CtsBionicTestCases CtsTextTestCases minikin_tests -- --abi x86_64 # the primary ABI` 365 366 6c. [No longer needed] Run the host-side test by 367 * ICU4J host-side test `ant check` 368 * ICU4C host-side test `make CINTLTST_OPTS=-w INTLTEST_OPTS=-w check` 369 (Currently, it has some failing tests. No of failures?) 370 371 6d. If libcore/ tests are changed, verify the change 372 * To verify the test change in ART MTS, run `m mts && mts-tradefed run mts-art` on Android S. 373 * To verify the test change on LUCI bot, run `art/tools/run-libcore-tests.sh --mode=host`, because LUCI uses older ICU versions. 374 3757. Upload the CLs to gerrit for code reviews from `aosp/icu${ICU_VERSION}` in `external/icu` and `aosp/upstream-release-cldr` in `external/cldr` 376 ```shell 377 repo upload --cbr -o nokeycheck -o uploadvalidator~skip --no-verify . 378 ``` 3798. Merge `aosp/icu*` branch to aosp/main 380 ```shell 381 cd $ANDROID_BUILD_TOP/external/icu 382 repo start icu${ICU_VERSION}-main . 383 git merge --no-ff icu${ICU_VERSION} -m " 384 Merge branch aosp/icu${ICU_VERSION} into aosp/main 385 386 Bug: ${ICU_UPGRADE_BUG} 387 Test: atest CtsIcu4cTestCases CtsIcuTestCases CtsLibcoreTestCases CtsLibcoreOjTestCases CtsBionicTestCases CtsTextTestCases minikin_tests 388 " 389 ``` 3909. Upload and submit changes from external/icu, external/cldr, libcore, frameworks/base, system/timezone 391 392 10a. `repo upload --cbr -o uploadvalidator~skip --no-verify .` 393 394 10b. Code review the diff in `android_icu4j/src/main/tests/android/icu/extratest/expected_transliteration_id_list.txt` 395 * If a transliteration id is removed from the list, it may introduce 396 app compatibility issues if the app depends on them. However, app 397 has been warned to check the availability before invoking them. 398 https://developer.android.com/reference/android/icu/text/Transliterator#getAvailableIDs() 39910. After submitting all the CLs to aosp/main, expose the new stable ICU4J APIs to Android SDK 400 ```shell 401 rm tools/srcgen/allowlisted-public-api.txt 402 ./tools/generate_android_icu4j.sh 403 # Modify Icu4jTransform.java to allowlist more classes if needed. Check the error message for the details 404 m update-api droid 405 406 git commit -a -F- <<EOF 407 Expose the new stable APIs from ICU4J ${ICU_VERSION} 408 409 According to the upstream API coverage report external/icu/icu4j/coverage-exclusion.txt, 410 the methods should have API coverage running in the existing CtsIcuTestCases. 411 412 Bug: ${ICU_UPGRADE_BUG} 413 Test: atest CtsIcuTestCases 414 EOF 415 ``` 41611. Send email android-libcore@ and icu-team@ to announce this. 417 1. Some Android teams may have dependency on the new ICU version for other features. 418 2. Email template 419 ```text 420 Hi, Libcore and ICU team, 421 422 ICU <version> just landed Android AOSP. 423 https://android.googlesource.com/platform/external/icu/+/main/README.version 424 as well as Android S (or Android 12). 425 https://googleplex-android.googlesource.com/platform/external/icu/+/sc-dev/README.version 426 427 Note: 428 - Contains bug fixes / build changes with a small set of API methods added. 429 - Unicode stays at version 14, and no new version has been published yet. 430 ``` 431 432 433## Historic version of this doc 434http://g3doc/third_party/icu/g3doc/update/android