OSDN Git Service

original
authorRO215IS01 <ro215is01@gmail.com>
Mon, 21 Feb 2011 10:15:04 +0000 (19:15 +0900)
committerRO215IS01 <ro215is01@gmail.com>
Mon, 21 Feb 2011 10:15:04 +0000 (19:15 +0900)
459 files changed:
build/CleanSpec.mk [new file with mode: 0644]
build/buildspec.mk.default [new file with mode: 0644]
build/core/Makefile [new file with mode: 0644]
build/core/apicheck_msg_current.txt [new file with mode: 0644]
build/core/apicheck_msg_last.txt [new file with mode: 0644]
build/core/armelf.x [new file with mode: 0644]
build/core/armelf.xsc [new file with mode: 0644]
build/core/armelflib.x [new file with mode: 0644]
build/core/base_rules.mk [new file with mode: 0644]
build/core/binary.mk [new file with mode: 0644]
build/core/build-system.html [new file with mode: 0644]
build/core/build_id.mk [new file with mode: 0644]
build/core/checktree [new file with mode: 0644]
build/core/cleanbuild.mk [new file with mode: 0644]
build/core/cleanspec.mk [new file with mode: 0644]
build/core/clear_vars.mk [new file with mode: 0644]
build/core/combo/HOST_darwin-x86.mk [new file with mode: 0644]
build/core/combo/HOST_linux-x86.mk [new file with mode: 0644]
build/core/combo/HOST_windows-x86.mk [new file with mode: 0644]
build/core/combo/TARGET_linux-arm.mk [new file with mode: 0644]
build/core/combo/TARGET_linux-sh.mk [new file with mode: 0644]
build/core/combo/TARGET_linux-x86.mk [new file with mode: 0644]
build/core/combo/arch/arm/armv4t.mk [new file with mode: 0644]
build/core/combo/arch/arm/armv5te-vfp.mk [new file with mode: 0644]
build/core/combo/arch/arm/armv5te.mk [new file with mode: 0644]
build/core/combo/arch/arm/armv7-a-neon.mk [new file with mode: 0644]
build/core/combo/arch/arm/armv7-a.mk [new file with mode: 0644]
build/core/combo/javac.mk [new file with mode: 0644]
build/core/combo/select.mk [new file with mode: 0644]
build/core/config.mk [new file with mode: 0644]
build/core/copy_headers.mk [new file with mode: 0644]
build/core/definitions.mk [new file with mode: 0644]
build/core/device.mk [new file with mode: 0644]
build/core/dex_preopt.mk [new file with mode: 0644]
build/core/distdir.mk [new file with mode: 0644]
build/core/droiddoc.mk [new file with mode: 0644]
build/core/dumpvar.mk [new file with mode: 0644]
build/core/dynamic_binary.mk [new file with mode: 0644]
build/core/envsetup.mk [new file with mode: 0644]
build/core/executable.mk [new file with mode: 0644]
build/core/filter_symbols.sh [new file with mode: 0644]
build/core/find-jdk-tools-jar.sh [new file with mode: 0644]
build/core/host_executable.mk [new file with mode: 0644]
build/core/host_java_library.mk [new file with mode: 0644]
build/core/host_prebuilt.mk [new file with mode: 0644]
build/core/host_shared_library.mk [new file with mode: 0644]
build/core/host_static_library.mk [new file with mode: 0644]
build/core/java.mk [new file with mode: 0644]
build/core/java_library.mk [new file with mode: 0644]
build/core/key_char_map.mk [new file with mode: 0644]
build/core/main.mk [new file with mode: 0644]
build/core/multi_prebuilt.mk [new file with mode: 0644]
build/core/node_fns.mk [new file with mode: 0644]
build/core/notice_files.mk [new file with mode: 0644]
build/core/package.mk [new file with mode: 0644]
build/core/pathmap.mk [new file with mode: 0644]
build/core/prebuilt.mk [new file with mode: 0644]
build/core/prelink-linux-arm.map [new file with mode: 0644]
build/core/process_wrapper.sh [new file with mode: 0644]
build/core/process_wrapper_gdb.cmds [new file with mode: 0644]
build/core/process_wrapper_gdb.sh [new file with mode: 0644]
build/core/product.mk [new file with mode: 0644]
build/core/product_config.mk [new file with mode: 0644]
build/core/proguard.flags [new file with mode: 0644]
build/core/proguard_tests.flags [new file with mode: 0644]
build/core/raw_executable.mk [new file with mode: 0644]
build/core/raw_static_library.mk [new file with mode: 0644]
build/core/root.mk [new file with mode: 0644]
build/core/shared_library.mk [new file with mode: 0644]
build/core/static_java_library.mk [new file with mode: 0644]
build/core/static_library.mk [new file with mode: 0644]
build/core/tasks/apicheck.mk [new file with mode: 0644]
build/core/tasks/cts.mk [new file with mode: 0644]
build/core/tasks/ide.mk [new file with mode: 0644]
build/core/tasks/product-graph.mk [new file with mode: 0644]
build/core/tasks/sdk-addon.mk [new file with mode: 0644]
build/core/user_tags.mk [new file with mode: 0644]
build/core/version_defaults.mk [new file with mode: 0644]
build/envsetup.sh [new file with mode: 0644]
build/libs/host/Android.mk [new file with mode: 0644]
build/libs/host/CopyFile.c [new file with mode: 0644]
build/libs/host/include/host/CopyFile.h [new file with mode: 0644]
build/libs/host/include/host/Directories.h [new file with mode: 0644]
build/libs/host/include/host/pseudolocalize.h [new file with mode: 0644]
build/libs/host/list.java [new file with mode: 0644]
build/libs/host/pseudolocalize.cpp [new file with mode: 0644]
build/target/board/Android.mk [new file with mode: 0644]
build/target/board/emulator/AndroidBoard.mk [new file with mode: 0644]
build/target/board/emulator/BoardConfig.mk [new file with mode: 0644]
build/target/board/emulator/README.txt [new file with mode: 0644]
build/target/board/emulator/tuttle2.kcm [new file with mode: 0644]
build/target/board/emulator/tuttle2.kl [new file with mode: 0644]
build/target/board/generic/AndroidBoard.mk [new file with mode: 0644]
build/target/board/generic/BoardConfig.mk [new file with mode: 0644]
build/target/board/generic/README.txt [new file with mode: 0644]
build/target/board/generic/device.mk [new file with mode: 0644]
build/target/board/generic/system.prop [new file with mode: 0644]
build/target/board/generic/tuttle2.kcm [new file with mode: 0644]
build/target/board/generic/tuttle2.kl [new file with mode: 0644]
build/target/board/generic_x86/AndroidBoard.mk [new file with mode: 0644]
build/target/board/generic_x86/BoardConfig.mk [new file with mode: 0644]
build/target/board/generic_x86/README.txt [new file with mode: 0644]
build/target/board/generic_x86/disk_layout.conf [new file with mode: 0644]
build/target/board/generic_x86/init.rc [new file with mode: 0644]
build/target/board/sim/AndroidBoard.mk [new file with mode: 0644]
build/target/board/sim/BoardConfig.mk [new file with mode: 0644]
build/target/product/AndroidProducts.mk [new file with mode: 0644]
build/target/product/core.mk [new file with mode: 0644]
build/target/product/full.mk [new file with mode: 0644]
build/target/product/full_base.mk [new file with mode: 0644]
build/target/product/full_x86.mk [new file with mode: 0644]
build/target/product/generic.mk [new file with mode: 0644]
build/target/product/generic_x86.mk [new file with mode: 0644]
build/target/product/languages_full.mk [new file with mode: 0644]
build/target/product/languages_small.mk [new file with mode: 0644]
build/target/product/locales_full.mk [new file with mode: 0644]
build/target/product/sdk.mk [new file with mode: 0644]
build/target/product/security/README [new file with mode: 0644]
build/target/product/security/media.pk8 [new file with mode: 0644]
build/target/product/security/media.x509.pem [new file with mode: 0644]
build/target/product/security/platform.pk8 [new file with mode: 0644]
build/target/product/security/platform.x509.pem [new file with mode: 0644]
build/target/product/security/shared.pk8 [new file with mode: 0644]
build/target/product/security/shared.x509.pem [new file with mode: 0644]
build/target/product/security/testkey.pk8 [new file with mode: 0644]
build/target/product/security/testkey.x509.pem [new file with mode: 0644]
build/target/product/sim.mk [new file with mode: 0644]
build/tools/Android.mk [new file with mode: 0644]
build/tools/acp/Android.mk [new file with mode: 0644]
build/tools/acp/README [new file with mode: 0644]
build/tools/acp/acp.c [new file with mode: 0644]
build/tools/adbs [new file with mode: 0644]
build/tools/apicheck/Android.mk [new file with mode: 0644]
build/tools/apicheck/etc/apicheck [new file with mode: 0644]
build/tools/apicheck/src/Android.mk [new file with mode: 0644]
build/tools/apicheck/src/MANIFEST.mf [new file with mode: 0644]
build/tools/apicheck/src/com/android/apicheck/AbstractMethodInfo.java [new file with mode: 0644]
build/tools/apicheck/src/com/android/apicheck/ApiCheck.java [new file with mode: 0644]
build/tools/apicheck/src/com/android/apicheck/ApiInfo.java [new file with mode: 0644]
build/tools/apicheck/src/com/android/apicheck/ClassInfo.java [new file with mode: 0644]
build/tools/apicheck/src/com/android/apicheck/ConstructorInfo.java [new file with mode: 0644]
build/tools/apicheck/src/com/android/apicheck/Errors.java [new file with mode: 0644]
build/tools/apicheck/src/com/android/apicheck/FieldInfo.java [new file with mode: 0644]
build/tools/apicheck/src/com/android/apicheck/MethodInfo.java [new file with mode: 0644]
build/tools/apicheck/src/com/android/apicheck/PackageInfo.java [new file with mode: 0644]
build/tools/apicheck/src/com/android/apicheck/ParameterInfo.java [new file with mode: 0644]
build/tools/apicheck/src/com/android/apicheck/SourcePositionInfo.java [new file with mode: 0644]
build/tools/apriori/Android.mk [new file with mode: 0644]
build/tools/apriori/apriori.c [new file with mode: 0644]
build/tools/apriori/apriori.h [new file with mode: 0644]
build/tools/apriori/cmdline.c [new file with mode: 0644]
build/tools/apriori/cmdline.h [new file with mode: 0644]
build/tools/apriori/common.h [new file with mode: 0644]
build/tools/apriori/debug.c [new file with mode: 0644]
build/tools/apriori/debug.h [new file with mode: 0644]
build/tools/apriori/hash.c [new file with mode: 0644]
build/tools/apriori/hash.h [new file with mode: 0644]
build/tools/apriori/main.c [new file with mode: 0644]
build/tools/apriori/prelink_info.c [new file with mode: 0644]
build/tools/apriori/prelink_info.h [new file with mode: 0644]
build/tools/apriori/prelinkmap.c [new file with mode: 0644]
build/tools/apriori/prelinkmap.h [new file with mode: 0644]
build/tools/apriori/rangesort.c [new file with mode: 0644]
build/tools/apriori/rangesort.h [new file with mode: 0644]
build/tools/apriori/source.c [new file with mode: 0644]
build/tools/apriori/source.h [new file with mode: 0644]
build/tools/apriori/tweak.h [new file with mode: 0644]
build/tools/atree/Android.mk [new file with mode: 0644]
build/tools/atree/atree.cpp [new file with mode: 0644]
build/tools/atree/files.cpp [new file with mode: 0644]
build/tools/atree/files.h [new file with mode: 0644]
build/tools/atree/fs.cpp [new file with mode: 0644]
build/tools/atree/fs.h [new file with mode: 0644]
build/tools/atree/options.h [new file with mode: 0644]
build/tools/bin2asm/Android.mk [new file with mode: 0644]
build/tools/bin2asm/data [new file with mode: 0644]
build/tools/bin2asm/icudata.c [new file with mode: 0644]
build/tools/buildinfo.sh [new file with mode: 0644]
build/tools/check_builds.sh [new file with mode: 0644]
build/tools/check_prereq/Android.mk [new file with mode: 0644]
build/tools/check_prereq/check_prereq.c [new file with mode: 0644]
build/tools/compare_fileslist.py [new file with mode: 0644]
build/tools/droiddoc/Android.mk [new file with mode: 0644]
build/tools/droiddoc/NOTICE [new file with mode: 0644]
build/tools/droiddoc/src/Android.mk [new file with mode: 0644]
build/tools/droiddoc/src/AnnotationInstanceInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/AnnotationValueInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/AttrTagInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/AttributeInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/ClassInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/ClearPage.java [new file with mode: 0644]
build/tools/droiddoc/src/Comment.java [new file with mode: 0644]
build/tools/droiddoc/src/ContainerInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/Converter.java [new file with mode: 0644]
build/tools/droiddoc/src/DocFile.java [new file with mode: 0644]
build/tools/droiddoc/src/DocInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/DroidDoc.java [new file with mode: 0644]
build/tools/droiddoc/src/Errors.java [new file with mode: 0644]
build/tools/droiddoc/src/FieldInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/Hierarchy.java [new file with mode: 0644]
build/tools/droiddoc/src/InheritedTags.java [new file with mode: 0644]
build/tools/droiddoc/src/KeywordEntry.java [new file with mode: 0644]
build/tools/droiddoc/src/LinkReference.java [new file with mode: 0644]
build/tools/droiddoc/src/LiteralTagInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/MemberInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/MethodInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/NavTree.java [new file with mode: 0644]
build/tools/droiddoc/src/PackageInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/ParamTagInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/ParameterInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/ParsedTagInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/Proofread.java [new file with mode: 0644]
build/tools/droiddoc/src/SampleCode.java [new file with mode: 0644]
build/tools/droiddoc/src/SampleTagInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/Scoped.java [new file with mode: 0644]
build/tools/droiddoc/src/SeeTagInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/SinceTagger.java [new file with mode: 0644]
build/tools/droiddoc/src/Sorter.java [new file with mode: 0644]
build/tools/droiddoc/src/SourcePositionInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/Stubs.java [new file with mode: 0644]
build/tools/droiddoc/src/TagInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/TextTagInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/ThrowsTagInfo.java [new file with mode: 0644]
build/tools/droiddoc/src/TodoFile.java [new file with mode: 0644]
build/tools/droiddoc/src/TypeInfo.java [new file with mode: 0644]
build/tools/droiddoc/templates-pdk/assets/android-developer-core.css [new file with mode: 0644]
build/tools/droiddoc/templates-pdk/assets/android-developer-docs.js [new file with mode: 0644]
build/tools/droiddoc/templates-pdk/assets/favicon.ico [new file with mode: 0644]
build/tools/droiddoc/templates-pdk/assets/images/rebox-gradient.gif [new file with mode: 0644]
build/tools/droiddoc/templates-pdk/assets/placeholder [new file with mode: 0644]
build/tools/droiddoc/templates-pdk/customization.cs [new file with mode: 0644]
build/tools/droiddoc/templates-pdk/data.hdf [new file with mode: 0644]
build/tools/droiddoc/templates-pdk/head_tag.cs [new file with mode: 0644]
build/tools/droiddoc/templates-sdk/assets-sdk/placeholder [new file with mode: 0644]
build/tools/droiddoc/templates-sdk/customization.cs [new file with mode: 0644]
build/tools/droiddoc/templates-sdk/data.hdf [new file with mode: 0644]
build/tools/droiddoc/templates-sdk/header_tabs.cs [new file with mode: 0644]
build/tools/droiddoc/templates-sdk/sdkpage.cs [new file with mode: 0644]
build/tools/droiddoc/templates/assets/android-developer-core.css [new file with mode: 0644]
build/tools/droiddoc/templates/assets/android-developer-docs-devguide.css [new file with mode: 0644]
build/tools/droiddoc/templates/assets/android-developer-docs.css [new file with mode: 0644]
build/tools/droiddoc/templates/assets/android-developer-docs.js [new file with mode: 0644]
build/tools/droiddoc/templates/assets/android-developer-reference.js [new file with mode: 0644]
build/tools/droiddoc/templates/assets/carousel.js [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/android-developers-logo.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/android_wrench.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/arrow_bluelink_down.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/arrow_bluelink_up.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/arrow_left_off.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/arrow_left_on.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/arrow_right_off.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/arrow_right_on.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/bg_community_leftDiv.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/bg_fade.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/bg_images_sprite.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/bg_logo.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/body-gradient-tab.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/body-gradient.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/developers-logo.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/grad-rule-qv.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/Android_Dev_Lab_l.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/IO-logo.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/adc2_l.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/adc2_s.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/android_adc.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/bg_home_announcement.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/bg_home_bottom.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/bg_home_carousel.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/bg_home_carousel_board.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/bg_home_carousel_wheel.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/carousel_buttons_sprite.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/devphone-large.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/devphone-small.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/donut-android.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/eclair-android.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/froyo-android.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/gdc-logo.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/gingerdroid.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/io-large.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/io-small.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/maps-large.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/maps-small.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/market-large.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/market-small.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/sdk-large.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/sdk-small.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/tv_l.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/home/tv_s.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/hr_gray_main.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/hr_gray_side.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/icon_contribute.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/icon_download.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/icon_download2.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/icon_guidelines_logo.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/icon_market.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/icon_robot.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/icon_world.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/left_off.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/left_on.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/logo_breadcrumbz.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/open_source.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/preliminary.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/resizable-e.gif [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/resizable-e2.gif [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/resizable-eg.gif [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/resizable-s.gif [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/resizable-s2.gif [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/resizable-sg.gif [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/right_off.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/right_on.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/sidenav-rule.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/slide_1.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/slide_2.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/slide_3.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/slide_large_1.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/slide_large_2.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/slide_large_3.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/slide_off.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/slide_on.jpg [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/spacer.gif [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/triangle-closed-small.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/triangle-closed.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/triangle-opened-small.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/triangle-opened.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/uiguidelines1.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/images/video-droid.png [new file with mode: 0644]
build/tools/droiddoc/templates/assets/jdiff_logo.gif [new file with mode: 0644]
build/tools/droiddoc/templates/assets/jquery-history.js [new file with mode: 0644]
build/tools/droiddoc/templates/assets/jquery-resizable.min.js [new file with mode: 0644]
build/tools/droiddoc/templates/assets/prettify.js [new file with mode: 0644]
build/tools/droiddoc/templates/assets/search_autocomplete.js [new file with mode: 0644]
build/tools/droiddoc/templates/assets/style.css [new file with mode: 0644]
build/tools/droiddoc/templates/assets/triangle-none.gif [new file with mode: 0644]
build/tools/droiddoc/templates/class.cs [new file with mode: 0644]
build/tools/droiddoc/templates/classes.cs [new file with mode: 0644]
build/tools/droiddoc/templates/customization.cs [new file with mode: 0644]
build/tools/droiddoc/templates/docpage.cs [new file with mode: 0644]
build/tools/droiddoc/templates/doctype.cs [new file with mode: 0644]
build/tools/droiddoc/templates/footer.cs [new file with mode: 0644]
build/tools/droiddoc/templates/head_tag.cs [new file with mode: 0644]
build/tools/droiddoc/templates/header.cs [new file with mode: 0644]
build/tools/droiddoc/templates/hierarchy.cs [new file with mode: 0644]
build/tools/droiddoc/templates/index.cs [new file with mode: 0644]
build/tools/droiddoc/templates/keywords.cs [new file with mode: 0644]
build/tools/droiddoc/templates/lists.cs [new file with mode: 0644]
build/tools/droiddoc/templates/macros.cs [new file with mode: 0644]
build/tools/droiddoc/templates/navtree_data.cs [new file with mode: 0644]
build/tools/droiddoc/templates/nosidenavpage.cs [new file with mode: 0644]
build/tools/droiddoc/templates/package-descr.cs [new file with mode: 0644]
build/tools/droiddoc/templates/package-list.cs [new file with mode: 0644]
build/tools/droiddoc/templates/package.cs [new file with mode: 0644]
build/tools/droiddoc/templates/packages.cs [new file with mode: 0644]
build/tools/droiddoc/templates/sample.cs [new file with mode: 0644]
build/tools/droiddoc/templates/sampleindex.cs [new file with mode: 0644]
build/tools/droiddoc/templates/todo.cs [new file with mode: 0644]
build/tools/droiddoc/templates/trailer.cs [new file with mode: 0644]
build/tools/droiddoc/test/generics/Android.mk [new file with mode: 0644]
build/tools/droiddoc/test/generics/src/com/android/generics/AbsListView.java [new file with mode: 0644]
build/tools/droiddoc/test/generics/src/com/android/generics/Adapter.java [new file with mode: 0644]
build/tools/droiddoc/test/generics/src/com/android/generics/AdapterView.java [new file with mode: 0644]
build/tools/droiddoc/test/generics/src/com/android/generics/Bar.java [new file with mode: 0644]
build/tools/droiddoc/test/generics/src/com/android/generics/Foo.java [new file with mode: 0644]
build/tools/droiddoc/test/generics/src/com/android/generics/FooBar.java [new file with mode: 0644]
build/tools/droiddoc/test/generics/src/com/android/generics/Iface.java [new file with mode: 0644]
build/tools/droiddoc/test/generics/src/com/android/generics/ListAdapter.java [new file with mode: 0644]
build/tools/droiddoc/test/generics/src/com/android/generics/TestComparable.java [new file with mode: 0644]
build/tools/droiddoc/test/generics/src/com/android/generics/TestEnum.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/Android.mk [new file with mode: 0644]
build/tools/droiddoc/test/stubs/expected/com/android/stubs/Annot.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/expected/com/android/stubs/InterfaceEnum.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/expected/com/android/stubs/Parent.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/expected/com/android/stubs/SomeEnum.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/expected/com/android/stubs/Types.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/expected/com/android/stubs/a/A.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/expected/com/android/stubs/a/SomeInterface.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/expected/com/android/stubs/b/B.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/func.sh [new file with mode: 0644]
build/tools/droiddoc/test/stubs/run.sh [new file with mode: 0644]
build/tools/droiddoc/test/stubs/src/com/android/stubs/Annot.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/src/com/android/stubs/InterfaceEnum.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/src/com/android/stubs/Parent.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/src/com/android/stubs/SomeEnum.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/src/com/android/stubs/Types.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/src/com/android/stubs/a/A.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/src/com/android/stubs/a/SomeInterface.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/src/com/android/stubs/b/B.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/src/com/android/stubs/hidden/Hidden.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/src/com/android/stubs/hidden/HiddenOuter.java [new file with mode: 0644]
build/tools/droiddoc/test/stubs/src/com/android/stubs/hidden/PackagePrivate.java [new file with mode: 0644]
build/tools/dump-package-stats [new file with mode: 0644]
build/tools/event_log_tags.py [new file with mode: 0644]
build/tools/fileslist.py [new file with mode: 0644]
build/tools/findleaves.py [new file with mode: 0644]
build/tools/fixlinebreaks.sh [new file with mode: 0644]
build/tools/fs_config/Android.mk [new file with mode: 0644]
build/tools/fs_config/fs_config.c [new file with mode: 0644]
build/tools/fs_get_stats/Android.mk [new file with mode: 0644]
build/tools/fs_get_stats/fs_get_stats.c [new file with mode: 0644]
build/tools/iself/Android.mk [new file with mode: 0644]
build/tools/iself/debug.h [new file with mode: 0644]
build/tools/iself/iself.c [new file with mode: 0644]
build/tools/isprelinked/Android.mk [new file with mode: 0644]
build/tools/isprelinked/common.h [new file with mode: 0644]
build/tools/isprelinked/debug.c [new file with mode: 0644]
build/tools/isprelinked/debug.h [new file with mode: 0644]
build/tools/isprelinked/isprelinked.c [new file with mode: 0644]
build/tools/isprelinked/prelink_info.c [new file with mode: 0644]
build/tools/isprelinked/prelink_info.h [new file with mode: 0644]
build/tools/java-event-log-tags.py [new file with mode: 0644]
build/tools/kcm/Android.mk [new file with mode: 0644]
build/tools/kcm/kcm.cpp [new file with mode: 0644]
build/tools/lsd/Android.mk [new file with mode: 0644]
build/tools/lsd/cmdline.c [new file with mode: 0644]
build/tools/lsd/cmdline.h [new file with mode: 0644]
build/tools/lsd/common.h [new file with mode: 0644]
build/tools/lsd/debug.c [new file with mode: 0644]
build/tools/lsd/debug.h [new file with mode: 0644]
build/tools/lsd/hash.c [new file with mode: 0644]
build/tools/lsd/hash.h [new file with mode: 0644]
build/tools/lsd/lsd.c [new file with mode: 0644]
build/tools/lsd/lsd.h [new file with mode: 0644]
build/tools/lsd/main.c [new file with mode: 0644]
build/tools/merge-event-log-tags.py [new file with mode: 0644]
build/tools/mktarball.sh [new file with mode: 0644]
build/tools/print_module_licenses.sh [new file with mode: 0644]
build/tools/releasetools/check_target_files_signatures [new file with mode: 0644]
build/tools/releasetools/common.py [new file with mode: 0644]
build/tools/releasetools/edify_generator.py [new file with mode: 0644]
build/tools/releasetools/img_from_target_files [new file with mode: 0644]
build/tools/releasetools/ota_from_target_files [new file with mode: 0644]
build/tools/releasetools/sign_target_files_apks [new file with mode: 0644]
build/tools/rgb2565/Android.mk [new file with mode: 0644]
build/tools/rgb2565/to565.c [new file with mode: 0644]
build/tools/signapk/Android.mk [new file with mode: 0644]
build/tools/signapk/SignApk.java [new file with mode: 0644]
build/tools/signapk/SignApk.mf [new file with mode: 0644]
build/tools/signapk/test/run [new file with mode: 0644]
build/tools/soslim/Android.mk [new file with mode: 0644]
build/tools/soslim/cmdline.c [new file with mode: 0644]
build/tools/soslim/cmdline.h [new file with mode: 0644]
build/tools/soslim/common.c [new file with mode: 0644]
build/tools/soslim/common.h [new file with mode: 0644]
build/tools/soslim/debug.c [new file with mode: 0644]
build/tools/soslim/debug.h [new file with mode: 0644]
build/tools/soslim/main.c [new file with mode: 0644]
build/tools/soslim/prelink_info.c [new file with mode: 0644]
build/tools/soslim/prelink_info.h [new file with mode: 0644]
build/tools/soslim/soslim.c [new file with mode: 0644]
build/tools/soslim/soslim.h [new file with mode: 0644]
build/tools/soslim/symfilter.c [new file with mode: 0644]
build/tools/soslim/symfilter.h [new file with mode: 0644]
build/tools/warn.py [new file with mode: 0644]
build/tools/zipalign/Android.mk [new file with mode: 0644]
build/tools/zipalign/README.txt [new file with mode: 0644]
build/tools/zipalign/ZipAlign.cpp [new file with mode: 0644]
build/tools/zipalign/ZipEntry.cpp [new file with mode: 0644]
build/tools/zipalign/ZipEntry.h [new file with mode: 0644]
build/tools/zipalign/ZipFile.cpp [new file with mode: 0644]
build/tools/zipalign/ZipFile.h [new file with mode: 0644]

diff --git a/build/CleanSpec.mk b/build/CleanSpec.mk
new file mode 100644 (file)
index 0000000..2663780
--- /dev/null
@@ -0,0 +1,56 @@
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libmediaplayerservice_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libmedia_jni_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libstagefright_omx_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/vendor)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/android-info.txt)
+$(call add-clean-step, find $(PRODUCT_OUT) -name "*.apk" | xargs rm)
+
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/build/buildspec.mk.default b/build/buildspec.mk.default
new file mode 100644 (file)
index 0000000..c568a82
--- /dev/null
@@ -0,0 +1,118 @@
+#
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+######################################################################
+# This is a do-nothing template file.  To use it, copy it to a file
+# named "buildspec.mk" in the root directory, and uncomment or change
+# the variables necessary for your desired configuration.  The file
+# "buildspec.mk" should never be checked in to source control.
+######################################################################
+
+# Choose a product to build for.  Look in the products directory for ones
+# that work.
+ifndef TARGET_PRODUCT
+#TARGET_PRODUCT:=generic
+endif
+
+# Choose a variant to build.  If you don't pick one, the default is eng.
+# User is what we ship.  Userdebug is that, with a few flags turned on
+# for debugging.  Eng has lots of extra tools for development.
+ifndef TARGET_BUILD_VARIANT
+#TARGET_BUILD_VARIANT:=user
+#TARGET_BUILD_VARIANT:=userdebug
+#TARGET_BUILD_VARIANT:=eng
+endif
+
+# Choose additional targets to always install, even when building
+# minimal targets like "make droid".  This takes simple target names
+# like "Browser" or "MyApp", the names used by LOCAL_MODULE or
+# LOCAL_PACKAGE_NAME.  Modules listed here will always be installed in
+# /system, even if they'd usually go in /data.
+ifndef CUSTOM_MODULES
+#CUSTOM_MODULES:=
+endif
+
+# Uncomment this if you want the simulator, otherwise, build for arm
+ifndef TARGET_SIMULATOR
+#TARGET_SIMULATOR:=true
+endif
+
+# Set this to debug or release if you care.  Otherwise, it defaults to
+# release for arm and debug for the simulator.
+ifndef TARGET_BUILD_TYPE
+#TARGET_BUILD_TYPE:=release
+#TARGET_BUILD_TYPE:=debug
+endif
+
+# Uncomment this if you want the host tools built in debug mode.  Otherwise
+# it defaults to release.
+ifndef HOST_BUILD_TYPE
+#HOST_BUILD_TYPE:=debug
+endif
+
+# Turn on debugging for selected modules.  If DEBUG_MODULE_<module-name> is set
+# to a non-empty value, the appropriate HOST_/TARGET_CUSTOM_DEBUG_CFLAGS
+# will be added to LOCAL_CFLAGS when building the module.
+#DEBUG_MODULE_ModuleName:=true
+
+# Specify an alternative tool chain prefix if needed.
+#TARGET_TOOLS_PREFIX:=
+
+# Specify the extra CFLAGS to use when building a module whose
+# DEBUG_MODULE_ variable is set.  Host and device flags are handled
+# separately.
+#HOST_CUSTOM_DEBUG_CFLAGS:=
+#TARGET_CUSTOM_DEBUG_CFLAGS:=
+
+# Choose additional locales, like "en_US" or "it_IT", to add to any
+# built product.  Any locales that appear in CUSTOM_LOCALES but not in
+# the locale list for the selected product will be added to the end
+# of PRODUCT_LOCALES.
+ifndef CUSTOM_LOCALES
+#CUSTOM_LOCALES:=
+endif
+
+# If you have a special place to put your ouput files, set this, otherwise
+# it goes to <build-root>/out
+#OUT_DIR:=/tmp/stuff
+
+# If you want to always set certain system properties, add them to this list.
+# E.g., "ADDITIONAL_BUILD_PROPERTIES += ro.prop1=5 prop2=value"
+# This mechanism does not currently support values containing spaces.
+#ADDITIONAL_BUILD_PROPERTIES +=
+
+# If you want to reduce the system.img size by several meg, and are willing to
+# lose access to CJK (and other) character sets, define NO_FALLBACK_FONT:=true
+ifndef NO_FALLBACK_FONT
+#NO_FALLBACK_FONT:=true
+endif
+
+# To enable instrumentation in webcore based apps like gmail and
+# the browser, define WEBCORE_INSTRUMENTATION:=true
+ifndef WEBCORE_INSTRUMENTATION
+#WEBCORE_INSTRUMENTATION:=true
+endif
+
+# To enable SVG in webcore define ENABLE_SVG:=true
+ifndef ENABLE_SVG
+#ENABLE_SVG:=true
+endif
+
+# when the build system changes such that this file must be updated, this
+# variable will be changed.  After you have modified this file with the new
+# changes (see buildspec.mk.default), update this to the new value from
+# buildspec.mk.default.
+BUILD_ENV_SEQUENCE_NUMBER := 10
diff --git a/build/core/Makefile b/build/core/Makefile
new file mode 100644 (file)
index 0000000..e577063
--- /dev/null
@@ -0,0 +1,1421 @@
+# Put some miscellaneous rules here
+
+# Pick a reasonable string to use to identify files.
+ifneq "" "$(filter eng.%,$(BUILD_NUMBER))"
+  # BUILD_NUMBER has a timestamp in it, which means that
+  # it will change every time.  Pick a stable value.
+  FILE_NAME_TAG := eng.$(USER)
+else
+  FILE_NAME_TAG := $(BUILD_NUMBER)
+endif
+
+# -----------------------------------------------------------------
+# Define rules to copy PRODUCT_COPY_FILES defined by the product.
+# PRODUCT_COPY_FILES contains words like <source file>:<dest file>.
+# <dest file> is relative to $(PRODUCT_OUT), so it should look like,
+# e.g., "system/etc/file.xml".
+# The filter part means "only eval the copy-one-file rule if this
+# src:dest pair is the first one to match %:dest"
+$(foreach cf,$(PRODUCT_COPY_FILES), \
+  $(eval _src := $(call word-colon,1,$(cf))) \
+  $(eval _dest := $(call word-colon,2,$(cf))) \
+  $(eval _fulldest := $(call append-path,$(PRODUCT_OUT),$(_dest))) \
+  $(if $(filter $(_src):$(_dest),$(firstword $(filter %:$(_dest),$(PRODUCT_COPY_FILES)))), \
+    $(eval $(call copy-one-file,$(_src),$(_fulldest))),) \
+  $(eval ALL_DEFAULT_INSTALLED_MODULES += $(_fulldest)) \
+ )
+
+# -----------------------------------------------------------------
+# docs/index.html
+gen := $(OUT_DOCS)/index.html
+ALL_DOCS += $(gen)
+$(gen): frameworks/base/docs/docs-redirect-index.html
+       @mkdir -p $(dir $@)
+       @cp -f $< $@
+
+# -----------------------------------------------------------------
+# default.prop
+INSTALLED_DEFAULT_PROP_TARGET := $(TARGET_ROOT_OUT)/default.prop
+ALL_DEFAULT_INSTALLED_MODULES += $(INSTALLED_DEFAULT_PROP_TARGET)
+ADDITIONAL_DEFAULT_PROPERTIES := \
+       $(call collapse-pairs, $(ADDITIONAL_DEFAULT_PROPERTIES))
+
+$(INSTALLED_DEFAULT_PROP_TARGET):
+       @echo Target buildinfo: $@
+       @mkdir -p $(dir $@)
+       $(hide) echo "#" > $@; \
+               echo "# ADDITIONAL_DEFAULT_PROPERTIES" >> $@; \
+               echo "#" >> $@;
+       $(hide) $(foreach line,$(ADDITIONAL_DEFAULT_PROPERTIES), \
+               echo "$(line)" >> $@;)
+
+# -----------------------------------------------------------------
+# build.prop
+INSTALLED_BUILD_PROP_TARGET := $(TARGET_OUT)/build.prop
+ALL_DEFAULT_INSTALLED_MODULES += $(INSTALLED_BUILD_PROP_TARGET)
+ADDITIONAL_BUILD_PROPERTIES := \
+       $(call collapse-pairs, $(ADDITIONAL_BUILD_PROPERTIES))
+
+# A list of arbitrary tags describing the build configuration.
+# Force ":=" so we can use +=
+BUILD_VERSION_TAGS := $(BUILD_VERSION_TAGS)
+ifeq ($(TARGET_BUILD_TYPE),debug)
+  BUILD_VERSION_TAGS += debug
+endif
+# Apps are always signed with test keys, and may be re-signed in a post-build
+# step.  If that happens, the "test-keys" tag will be removed by that step.
+BUILD_VERSION_TAGS += test-keys
+BUILD_VERSION_TAGS := $(subst $(space),$(comma),$(sort $(BUILD_VERSION_TAGS)))
+
+# A human-readable string that descibes this build in detail.
+build_desc := $(TARGET_PRODUCT)-$(TARGET_BUILD_VARIANT) $(PLATFORM_VERSION) $(BUILD_ID) $(BUILD_NUMBER) $(BUILD_VERSION_TAGS)
+$(INSTALLED_BUILD_PROP_TARGET): PRIVATE_BUILD_DESC := $(build_desc)
+
+# The string used to uniquely identify this build;  used by the OTA server.
+ifeq (,$(strip $(BUILD_FINGERPRINT)))
+  BUILD_FINGERPRINT := $(PRODUCT_BRAND)/$(TARGET_PRODUCT)/$(TARGET_DEVICE):$(PLATFORM_VERSION)/$(BUILD_ID)/$(BUILD_NUMBER):$(TARGET_BUILD_VARIANT)/$(BUILD_VERSION_TAGS)
+endif
+ifneq ($(words $(BUILD_FINGERPRINT)),1)
+  $(error BUILD_FINGERPRINT cannot contain spaces: "$(BUILD_FINGERPRINT)")
+endif
+
+# Display parameters shown under Settings -> About Phone
+ifeq ($(TARGET_BUILD_VARIANT),user)
+  # User builds should show:
+  # release build number or branch.buld_number non-release builds
+
+  # Dev. branches should have DISPLAY_BUILD_NUMBER set
+  ifeq "true" "$(DISPLAY_BUILD_NUMBER)"
+    BUILD_DISPLAY_ID := $(BUILD_ID).$(BUILD_NUMBER)
+  else
+    BUILD_DISPLAY_ID := $(BUILD_ID)
+  endif
+else
+  # Non-user builds should show detailed build information
+  BUILD_DISPLAY_ID := $(build_desc)
+endif
+
+# Selects the first locale in the list given as the argument,
+# and splits it into language and region, which each may be
+# empty.
+define default-locale
+$(subst _, , $(firstword $(1)))
+endef
+
+# Selects the first locale in the list given as the argument
+# and returns the language (or the region)
+define default-locale-language
+$(word 2, 2, $(call default-locale, $(1)))
+endef
+define default-locale-region
+$(word 3, 3, $(call default-locale, $(1)))
+endef
+
+BUILDINFO_SH := build/tools/buildinfo.sh
+$(INSTALLED_BUILD_PROP_TARGET): $(BUILDINFO_SH) $(INTERNAL_BUILD_ID_MAKEFILE) $(BUILD_SYSTEM)/version_defaults.mk $(wildcard $(TARGET_DEVICE_DIR)/system.prop)
+       @echo Target buildinfo: $@
+       @mkdir -p $(dir $@)
+       $(hide) TARGET_BUILD_TYPE="$(TARGET_BUILD_VARIANT)" \
+                       TARGET_DEVICE="$(TARGET_DEVICE)" \
+                       PRODUCT_NAME="$(TARGET_PRODUCT)" \
+                       PRODUCT_BRAND="$(PRODUCT_BRAND)" \
+                       PRODUCT_DEFAULT_LANGUAGE="$(call default-locale-language,$(PRODUCT_LOCALES))" \
+                       PRODUCT_DEFAULT_REGION="$(call default-locale-region,$(PRODUCT_LOCALES))" \
+                       PRODUCT_DEFAULT_WIFI_CHANNELS="$(PRODUCT_DEFAULT_WIFI_CHANNELS)" \
+                       PRODUCT_MODEL="$(PRODUCT_MODEL)" \
+                       PRODUCT_MANUFACTURER="$(PRODUCT_MANUFACTURER)" \
+                       PRIVATE_BUILD_DESC="$(PRIVATE_BUILD_DESC)" \
+                       BUILD_ID="$(BUILD_ID)" \
+                       BUILD_DISPLAY_ID="$(BUILD_DISPLAY_ID)" \
+                       BUILD_NUMBER="$(BUILD_NUMBER)" \
+                       PLATFORM_VERSION="$(PLATFORM_VERSION)" \
+                       PLATFORM_SDK_VERSION="$(PLATFORM_SDK_VERSION)" \
+                       PLATFORM_VERSION_CODENAME="$(PLATFORM_VERSION_CODENAME)" \
+                       BUILD_VERSION_TAGS="$(BUILD_VERSION_TAGS)" \
+                       TARGET_BOOTLOADER_BOARD_NAME="$(TARGET_BOOTLOADER_BOARD_NAME)" \
+                       BUILD_FINGERPRINT="$(BUILD_FINGERPRINT)" \
+                       TARGET_BOARD_PLATFORM="$(TARGET_BOARD_PLATFORM)" \
+                       TARGET_CPU_ABI="$(TARGET_CPU_ABI)" \
+                       TARGET_CPU_ABI2="$(TARGET_CPU_ABI2)" \
+               bash $(BUILDINFO_SH) > $@
+       $(hide) if [ -f $(TARGET_DEVICE_DIR)/system.prop ]; then \
+                 cat $(TARGET_DEVICE_DIR)/system.prop >> $@; \
+               fi
+       $(if $(ADDITIONAL_BUILD_PROPERTIES), \
+               $(hide) echo >> $@; \
+                       echo "#" >> $@; \
+                       echo "# ADDITIONAL_BUILD_PROPERTIES" >> $@; \
+                       echo "#" >> $@; )
+       $(hide) $(foreach line,$(ADDITIONAL_BUILD_PROPERTIES), \
+               echo "$(line)" >> $@;)
+
+build_desc :=
+
+# -----------------------------------------------------------------
+# sdk-build.prop
+#
+# There are certain things in build.prop that we don't want to
+# ship with the sdk; remove them.
+
+# This must be a list of entire property keys followed by
+# "=" characters, without any internal spaces.
+sdk_build_prop_remove := \
+       ro.build.user= \
+       ro.build.host= \
+       ro.product.brand= \
+       ro.product.manufacturer= \
+       ro.product.device=
+# TODO: Remove this soon-to-be obsolete property
+sdk_build_prop_remove += ro.build.product=
+INSTALLED_SDK_BUILD_PROP_TARGET := $(PRODUCT_OUT)/sdk/sdk-build.prop
+$(INSTALLED_SDK_BUILD_PROP_TARGET): $(INSTALLED_BUILD_PROP_TARGET)
+       @echo SDK buildinfo: $@
+       @mkdir -p $(dir $@)
+       $(hide) grep -v "$(subst $(space),\|,$(strip \
+                               $(sdk_build_prop_remove)))" $< > $@.tmp
+       $(hide) for x in $(sdk_build_prop_remove); do \
+                               echo "$$x"generic >> $@.tmp; done
+       $(hide) mv $@.tmp $@
+
+# -----------------------------------------------------------------
+# package stats
+PACKAGE_STATS_FILE := $(PRODUCT_OUT)/package-stats.txt
+PACKAGES_TO_STAT := \
+    $(sort $(filter $(TARGET_OUT)/% $(TARGET_OUT_DATA)/%, \
+       $(filter %.jar %.apk, $(ALL_DEFAULT_INSTALLED_MODULES))))
+$(PACKAGE_STATS_FILE): $(PACKAGES_TO_STAT)
+       @echo Package stats: $@
+       @mkdir -p $(dir $@)
+       $(hide) rm -f $@
+       $(hide) build/tools/dump-package-stats $^ > $@
+
+.PHONY: package-stats
+package-stats: $(PACKAGE_STATS_FILE)
+
+# -----------------------------------------------------------------
+# Cert-to-package mapping.  Used by the post-build signing tools.
+name := $(TARGET_PRODUCT)
+ifeq ($(TARGET_BUILD_TYPE),debug)
+  name := $(name)_debug
+endif
+name := $(name)-apkcerts-$(FILE_NAME_TAG)
+intermediates := \
+       $(call intermediates-dir-for,PACKAGING,apkcerts)
+APKCERTS_FILE := $(intermediates)/$(name).txt
+# Depending on the built packages isn't exactly right,
+# but it should guarantee that the apkcerts file is rebuilt
+# if any packages change which certs they're signed with.
+all_built_packages := $(foreach p,$(PACKAGES),$(ALL_MODULES.$(p).BUILT))
+ifneq ($(TARGET_BUILD_APPS),)
+# We don't need to really build all the modules for apps_only build.
+$(APKCERTS_FILE):
+else
+$(APKCERTS_FILE): $(all_built_packages)
+endif
+       @echo APK certs list: $@
+       @mkdir -p $(dir $@)
+       @rm -f $@
+       $(hide) $(foreach p,$(PACKAGES),\
+          $(if $(PACKAGES.$(p).EXTERNAL_KEY),\
+           echo 'name="$(p).apk" certificate="EXTERNAL" \
+                private_key=""' >> $@;,\
+           echo 'name="$(p).apk" certificate="$(PACKAGES.$(p).CERTIFICATE)" \
+                private_key="$(PACKAGES.$(p).PRIVATE_KEY)"' >> $@;))
+
+.PHONY: apkcerts-list
+apkcerts-list: $(APKCERTS_FILE)
+
+$(call dist-for-goals, apps_only, $(APKCERTS_FILE):apkcerts.txt)
+
+# -----------------------------------------------------------------
+# module info file
+ifdef CREATE_MODULE_INFO_FILE
+  MODULE_INFO_FILE := $(PRODUCT_OUT)/module-info.txt
+  $(info Generating $(MODULE_INFO_FILE)...)
+  $(shell rm -f $(MODULE_INFO_FILE))
+  $(foreach m,$(ALL_MODULES), \
+    $(shell echo "NAME=\"$(m)\"" \
+       "PATH=\"$(strip $(ALL_MODULES.$(m).PATH))\"" \
+       "TAGS=\"$(strip $(filter-out _%,$(ALL_MODULES.$(m).TAGS)))\"" \
+       "BUILT=\"$(strip $(ALL_MODULES.$(m).BUILT))\"" \
+       "INSTALLED=\"$(strip $(ALL_MODULES.$(m).INSTALLED))\"" >> $(MODULE_INFO_FILE)))
+endif
+
+# -----------------------------------------------------------------
+
+# The test key is used to sign this package, and as the key required
+# for future OTA packages installed by this system.  Actual product
+# deliverables will be re-signed by hand.  We expect this file to
+# exist with the suffixes ".x509.pem" and ".pk8".
+DEFAULT_KEY_CERT_PAIR := $(SRC_TARGET_DIR)/product/security/testkey
+
+
+# Rules that need to be present for the simulator, even
+# if they don't do anything.
+.PHONY: systemimage
+systemimage:
+
+# -----------------------------------------------------------------
+
+.PHONY: event-log-tags
+
+# Produce an event logs tag file for everything we know about, in order
+# to properly allocate numbers.  Then produce a file that's filtered
+# for what's going to be installed.
+
+all_event_log_tags_file := $(TARGET_OUT_COMMON_INTERMEDIATES)/all-event-log-tags.txt
+
+# Include tags from all packages that we know about
+all_event_log_tags_src := \
+    $(sort $(foreach m, $(ALL_MODULES), $(ALL_MODULES.$(m).EVENT_LOG_TAGS)))
+
+$(all_event_log_tags_file): PRIVATE_SRC_FILES := $(all_event_log_tags_src)
+$(all_event_log_tags_file): $(all_event_log_tags_src)
+       $(hide) mkdir -p $(dir $@)
+       $(hide) build/tools/merge-event-log-tags.py -o $@ $(PRIVATE_SRC_FILES)
+
+
+event_log_tags_file := $(TARGET_OUT)/etc/event-log-tags
+
+# Include tags from all packages included in this product.
+event_log_tags_src := \
+    $(sort $(foreach m,\
+      $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGES) \
+      $(call module-names-for-tag-list,user), \
+      $(ALL_MODULES.$(m).EVENT_LOG_TAGS)))
+
+$(event_log_tags_file): PRIVATE_SRC_FILES := $(event_log_tags_src)
+$(event_log_tags_file): PRIVATE_MERGED_FILE := $(all_event_log_tags_file)
+$(event_log_tags_file): $(event_log_tags_src) $(all_event_log_tags_file)
+       $(hide) mkdir -p $(dir $@)
+       $(hide) build/tools/merge-event-log-tags.py -o $@ -m $(PRIVATE_MERGED_FILE) $(PRIVATE_SRC_FILES)
+
+event-log-tags: $(event_log_tags_file)
+
+ALL_DEFAULT_INSTALLED_MODULES += $(event_log_tags_file)
+
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+# #################################################################
+# Targets for boot/OS images
+# #################################################################
+
+# -----------------------------------------------------------------
+# the ramdisk
+INTERNAL_RAMDISK_FILES := $(filter $(TARGET_ROOT_OUT)/%, \
+       $(ALL_PREBUILT) \
+       $(ALL_COPIED_HEADERS) \
+       $(ALL_GENERATED_SOURCES) \
+       $(ALL_DEFAULT_INSTALLED_MODULES))
+
+BUILT_RAMDISK_TARGET := $(PRODUCT_OUT)/ramdisk.img
+
+# We just build this directly to the install location.
+INSTALLED_RAMDISK_TARGET := $(BUILT_RAMDISK_TARGET)
+$(INSTALLED_RAMDISK_TARGET): $(MKBOOTFS) $(INTERNAL_RAMDISK_FILES) | $(MINIGZIP)
+       $(call pretty,"Target ram disk: $@")
+       $(hide) $(MKBOOTFS) $(TARGET_ROOT_OUT) | $(MINIGZIP) > $@
+
+
+ifneq ($(strip $(TARGET_NO_KERNEL)),true)
+
+# -----------------------------------------------------------------
+# the boot image, which is a collection of other images.
+INTERNAL_BOOTIMAGE_ARGS := \
+       $(addprefix --second ,$(INSTALLED_2NDBOOTLOADER_TARGET)) \
+       --kernel $(INSTALLED_KERNEL_TARGET) \
+       --ramdisk $(INSTALLED_RAMDISK_TARGET)
+
+INTERNAL_BOOTIMAGE_FILES := $(filter-out --%,$(INTERNAL_BOOTIMAGE_ARGS))
+
+BOARD_KERNEL_CMDLINE := $(strip $(BOARD_KERNEL_CMDLINE))
+ifdef BOARD_KERNEL_CMDLINE
+  INTERNAL_BOOTIMAGE_ARGS += --cmdline "$(BOARD_KERNEL_CMDLINE)"
+endif
+
+BOARD_KERNEL_BASE := $(strip $(BOARD_KERNEL_BASE))
+ifdef BOARD_KERNEL_BASE
+  INTERNAL_BOOTIMAGE_ARGS += --base $(BOARD_KERNEL_BASE)
+endif
+
+BOARD_KERNEL_PAGESIZE := $(strip $(BOARD_KERNEL_PAGESIZE))
+ifdef BOARD_KERNEL_PAGESIZE
+  INTERNAL_BOOTIMAGE_ARGS += --pagesize $(BOARD_KERNEL_PAGESIZE)
+endif
+
+INSTALLED_BOOTIMAGE_TARGET := $(PRODUCT_OUT)/boot.img
+
+ifeq ($(TARGET_BOOTIMAGE_USE_EXT2),true)
+tmp_dir_for_image := $(call intermediates-dir-for,EXECUTABLES,boot_img)/bootimg
+INTERNAL_BOOTIMAGE_ARGS += --tmpdir $(tmp_dir_for_image)
+INTERNAL_BOOTIMAGE_ARGS += --genext2fs $(MKEXT2IMG)
+$(INSTALLED_BOOTIMAGE_TARGET): $(MKEXT2IMG) $(INTERNAL_BOOTIMAGE_FILES)
+       $(call pretty,"Target boot image: $@")
+       $(hide) $(MKEXT2BOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) --output $@
+
+else # TARGET_BOOTIMAGE_USE_EXT2 != true
+
+$(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_FILES)
+       $(call pretty,"Target boot image: $@")
+       $(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) --output $@
+       $(hide) $(call assert-max-image-size,$@,$(BOARD_BOOTIMAGE_PARTITION_SIZE),raw)
+endif # TARGET_BOOTIMAGE_USE_EXT2
+
+else   # TARGET_NO_KERNEL
+# HACK: The top-level targets depend on the bootimage.  Not all targets
+# can produce a bootimage, though, and emulator targets need the ramdisk
+# instead.  Fake it out by calling the ramdisk the bootimage.
+# TODO: make the emulator use bootimages, and make mkbootimg accept
+#       kernel-less inputs.
+INSTALLED_BOOTIMAGE_TARGET := $(INSTALLED_RAMDISK_TARGET)
+endif
+
+# -----------------------------------------------------------------
+# NOTICE files
+#
+# This needs to be before the systemimage rules, because it adds to
+# ALL_DEFAULT_INSTALLED_MODULES, which those use to pick which files
+# go into the systemimage.
+
+.PHONY: notice_files
+
+# Create the rule to combine the files into text and html forms
+# $(1) - Plain text output file
+# $(2) - HTML output file
+# $(3) - File title
+# $(4) - Directory to use.  Notice files are all $(4)/src.  Other
+#               directories in there will be used for scratch
+# $(5) - Dependencies for the output files
+#
+# The algorithm here is that we go collect a hash for each of the notice
+# files and write the names of the files that match that hash.  Then
+# to generate the real files, we go print out all of the files and their
+# hashes.
+#
+# These rules are fairly complex, so they depend on this makefile so if
+# it changes, they'll run again.
+#
+# TODO: We could clean this up so that we just record the locations of the
+# original notice files instead of making rules to copy them somwehere.
+# Then we could traverse that without quite as much bash drama.
+define combine-notice-files
+$(1) $(2): PRIVATE_MESSAGE := $(3)
+$(1) $(2) $(4)/hash-timestamp: PRIVATE_DIR := $(4)
+$(4)/hash-timestamp: $(5) $(BUILD_SYSTEM)/Makefile
+       @echo Finding NOTICE files: $$@
+       $$(hide) rm -rf $$@ $$(PRIVATE_DIR)/hash
+       $$(hide) mkdir -p $$(PRIVATE_DIR)/hash
+       $$(hide) for file in $$$$(find $$(PRIVATE_DIR)/src -type f); do \
+                       hash=$$$$($(MD5SUM) $$$$file | sed -e "s/ .*//"); \
+                       hashfile=$$(PRIVATE_DIR)/hash/$$$$hash; \
+                       echo $$$$file >> $$$$hashfile; \
+               done
+       $$(hide) touch $$@
+$(1): $(4)/hash-timestamp
+       @echo Combining NOTICE files: $$@
+       $$(hide) mkdir -p $$(dir $$@)
+       $$(hide) echo $$(PRIVATE_MESSAGE) > $$@
+       $$(hide) find $$(PRIVATE_DIR)/hash -type f | xargs cat | sort | \
+               sed -e "s:$$(PRIVATE_DIR)/src\(.*\)\.txt:  \1:" >> $$@
+       $$(hide) echo >> $$@
+       $$(hide) echo >> $$@
+       $$(hide) echo >> $$@
+       $$(hide) for hashfile in $$$$(find $$(PRIVATE_DIR)/hash -type f); do \
+                       echo "============================================================"\
+                               >> $$@; \
+                       echo "Notices for file(s):" >> $$@; \
+                       cat $$$$hashfile | sort | \
+                               sed -e "s:$$(PRIVATE_DIR)/src\(.*\)\.txt:  \1:" >> \
+                               $$@; \
+                       echo "------------------------------------------------------------"\
+                               >> $$@; \
+                       echo >> $$@; \
+                       orig=$$$$(head -n 1 $$$$hashfile); \
+                       cat $$$$orig >> $$@; \
+                       echo >> $$@; \
+                       echo >> $$@; \
+                       echo >> $$@; \
+               done
+$(2): $(4)/hash-timestamp
+       @echo Combining NOTICE files: $$@
+       $$(hide) mkdir -p $$(dir $$@)
+       $$(hide) echo "<html><head>" > $$@
+       $$(hide) echo "<style type=\"text/css\">" >> $$@
+       $$(hide) echo "body { padding: 0; font-family: sans-serif; }" >> $$@
+       $$(hide) echo ".same-license { background-color: #eeeeee; border-top: 20px solid white; padding: 10px; }" >> $$@
+       $$(hide) echo ".label { font-weight: bold; }" >> $$@
+       $$(hide) echo ".file-list { margin-left: 1em; font-color: blue; }" >> $$@
+       $$(hide) echo "</style>" >> $$@
+       $$(hide) echo "</head><body topmargin=\"0\" leftmargin=\"0\" rightmargin=\"0\" bottommargin=\"0\">" >> $$@
+       $$(hide) echo "<table cellpading=\"0\" cellspacing=\"0\" border=\"0\">" \
+               >> $$@
+       $$(hide) for hashfile in $$$$(find $$(PRIVATE_DIR)/hash -type f); do \
+                       cat $$$$hashfile | sort | \
+                               sed -e "s:$$(PRIVATE_DIR)/src\(.*\)\.txt:  <a name=\"\1\"></a>:" >> \
+                               $$@; \
+                       echo "<tr><td class=\"same-license\">" >> $$@; \
+                       echo "<div class=\"label\">Notices for file(s):</div>" >> $$@; \
+                       echo "<div class=\"file-list\">" >> $$@; \
+                       cat $$$$hashfile | sort | \
+                               sed -e "s:$$(PRIVATE_DIR)/src\(.*\)\.txt:  \1<br/>:" >> $$@; \
+                       echo "</div><!-- file-list -->" >> $$@; \
+                       echo >> $$@; \
+                       orig=$$$$(head -n 1 $$$$hashfile); \
+                       echo "<pre class=\"license-text\">" >> $$@; \
+                       cat $$$$orig | sed -e "s/\&/\&amp;/g" | sed -e "s/</\&lt;/g" \
+                                       | sed -e "s/>/\&gt;/g" >> $$@; \
+                       echo "</pre><!-- license-text -->" >> $$@; \
+                       echo "</td></tr><!-- same-license -->" >> $$@; \
+                       echo >> $$@; \
+                       echo >> $$@; \
+                       echo >> $$@; \
+               done
+       $$(hide) echo "</table>" >> $$@
+       $$(hide) echo "</body></html>" >> $$@
+notice_files: $(1) $(2)
+endef
+
+# TODO These intermediate NOTICE.txt/NOTICE.html files should go into
+# TARGET_OUT_NOTICE_FILES now that the notice files are gathered from
+# the src subdirectory.
+
+target_notice_file_txt := $(TARGET_OUT_INTERMEDIATES)/NOTICE.txt
+target_notice_file_html := $(TARGET_OUT_INTERMEDIATES)/NOTICE.html
+target_notice_file_html_gz := $(TARGET_OUT_INTERMEDIATES)/NOTICE.html.gz
+tools_notice_file_txt := $(HOST_OUT_INTERMEDIATES)/NOTICE.txt
+tools_notice_file_html := $(HOST_OUT_INTERMEDIATES)/NOTICE.html
+
+kernel_notice_file := $(TARGET_OUT_NOTICE_FILES)/src/kernel.txt
+
+$(eval $(call combine-notice-files, \
+                       $(target_notice_file_txt), \
+                       $(target_notice_file_html), \
+                       "Notices for files contained in the filesystem images in this directory:", \
+                       $(TARGET_OUT_NOTICE_FILES), \
+                       $(ALL_DEFAULT_INSTALLED_MODULES) $(kernel_notice_file)))
+
+$(eval $(call combine-notice-files, \
+                       $(tools_notice_file_txt), \
+                       $(tools_notice_file_html), \
+                       "Notices for files contained in the tools directory:", \
+                       $(HOST_OUT_NOTICE_FILES), \
+                       $(ALL_DEFAULT_INSTALLED_MODULES)))
+
+# Install the html file at /system/etc/NOTICE.html.gz.
+# This is not ideal, but this is very late in the game, after a lot of
+# the module processing has already been done -- in fact, we used the
+# fact that all that has been done to get the list of modules that we
+# need notice files for.
+$(target_notice_file_html_gz): $(target_notice_file_html) | $(MINIGZIP)
+       $(hide) $(MINIGZIP) -9 < $< > $@
+installed_notice_html_gz := $(TARGET_OUT)/etc/NOTICE.html.gz
+$(installed_notice_html_gz): $(target_notice_file_html_gz) | $(ACP)
+       $(copy-file-to-target)
+
+# if we've been run my mm, mmm, etc, don't reinstall this every time
+ifeq ($(ONE_SHOT_MAKEFILE),)
+ALL_DEFAULT_INSTALLED_MODULES += $(installed_notice_html_gz)
+endif
+
+# The kernel isn't really a module, so to get its module file in there, we
+# make the target NOTICE files depend on this particular file too, which will
+# then be in the right directory for the find in combine-notice-files to work.
+$(kernel_notice_file): \
+           prebuilt/$(TARGET_PREBUILT_TAG)/kernel/LINUX_KERNEL_COPYING \
+           | $(ACP)
+       @echo Copying: $@
+       $(hide) mkdir -p $(dir $@)
+       $(hide) $(ACP) $< $@
+
+
+# -----------------------------------------------------------------
+# Build a keystore with the authorized keys in it, used to verify the
+# authenticity of downloaded OTA packages.
+#
+# This rule adds to ALL_DEFAULT_INSTALLED_MODULES, so it needs to come
+# before the rules that use that variable to build the image.
+ALL_DEFAULT_INSTALLED_MODULES += $(TARGET_OUT_ETC)/security/otacerts.zip
+$(TARGET_OUT_ETC)/security/otacerts.zip: KEY_CERT_PAIR := $(DEFAULT_KEY_CERT_PAIR)
+$(TARGET_OUT_ETC)/security/otacerts.zip: $(addsuffix .x509.pem,$(DEFAULT_KEY_CERT_PAIR))
+       $(hide) rm -f $@
+       $(hide) mkdir -p $(dir $@)
+       $(hide) zip -qj $@ $<
+
+.PHONY: otacerts
+otacerts: $(TARGET_OUT_ETC)/security/otacerts.zip
+
+
+# #################################################################
+# Targets for user images
+# #################################################################
+
+INTERNAL_USERIMAGES_EXT_VARIANT :=
+ifeq ($(TARGET_USERIMAGES_USE_EXT2),true)
+INTERNAL_USERIMAGES_USE_EXT := true
+INTERNAL_USERIMAGES_EXT_VARIANT := ext2
+else
+ifeq ($(TARGET_USERIMAGES_USE_EXT3),true)
+INTERNAL_USERIMAGES_USE_EXT := true
+INTERNAL_USERIMAGES_EXT_VARIANT := ext3
+else
+ifeq ($(TARGET_USERIMAGES_USE_EXT4),true)
+INTERNAL_USERIMAGES_USE_EXT := true
+INTERNAL_USERIMAGES_EXT_VARIANT := ext4
+endif
+endif
+endif
+
+ifneq (true,$(TARGET_USERIMAGES_SPARSE_EXT_DISABLED))
+  INTERNAL_USERIMAGES_SPARSE_EXT_FLAG := -s
+endif
+
+ifeq ($(INTERNAL_USERIMAGES_USE_EXT),true)
+INTERNAL_USERIMAGES_DEPS := $(MKEXTUSERIMG) $(MAKE_EXT4FS)
+INTERNAL_USERIMAGES_BINARY_PATHS := $(sort $(dir $(INTERNAL_USERIMAGES_DEPS)))
+
+# $(1): src directory
+# $(2): output file
+# $(3): mount point
+# $(4): ext variant (ext2, ext3, ext4)
+# $(5): size of the partition
+define build-userimage-ext-target
+  @mkdir -p $(dir $(2))
+  $(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$(PATH) \
+         $(MKEXTUSERIMG) $(INTERNAL_USERIMAGES_SPARSE_EXT_FLAG) $(1) $(2) $(4) $(3) $(5)
+endef
+else
+INTERNAL_USERIMAGES_DEPS := $(MKYAFFS2)
+endif
+
+# -----------------------------------------------------------------
+# Recovery image
+
+# If neither TARGET_NO_KERNEL nor TARGET_NO_RECOVERY are true
+ifeq (,$(filter true, $(TARGET_NO_KERNEL) $(TARGET_NO_RECOVERY) $(BUILD_TINY_ANDROID)))
+
+INSTALLED_RECOVERYIMAGE_TARGET := $(PRODUCT_OUT)/recovery.img
+
+recovery_initrc := $(call include-path-for, recovery)/etc/init.rc
+recovery_kernel := $(INSTALLED_KERNEL_TARGET) # same as a non-recovery system
+recovery_ramdisk := $(PRODUCT_OUT)/ramdisk-recovery.img
+recovery_build_prop := $(INSTALLED_BUILD_PROP_TARGET)
+recovery_binary := $(call intermediates-dir-for,EXECUTABLES,recovery)/recovery
+recovery_resources_common := $(call include-path-for, recovery)/res
+recovery_resources_private := $(strip $(wildcard $(TARGET_DEVICE_DIR)/recovery/res))
+recovery_resource_deps := $(shell find $(recovery_resources_common) \
+  $(recovery_resources_private) -type f)
+recovery_fstab := $(strip $(wildcard $(TARGET_DEVICE_DIR)/recovery.fstab))
+
+ifeq ($(recovery_resources_private),)
+  $(info No private recovery resources for TARGET_DEVICE $(TARGET_DEVICE))
+endif
+
+ifeq ($(recovery_fstab),)
+  $(info No recovery.fstab for TARGET_DEVICE $(TARGET_DEVICE))
+endif
+
+INTERNAL_RECOVERYIMAGE_ARGS := \
+       $(addprefix --second ,$(INSTALLED_2NDBOOTLOADER_TARGET)) \
+       --kernel $(recovery_kernel) \
+       --ramdisk $(recovery_ramdisk)
+
+# Assumes this has already been stripped
+ifdef BOARD_KERNEL_CMDLINE
+  INTERNAL_RECOVERYIMAGE_ARGS += --cmdline "$(BOARD_KERNEL_CMDLINE)"
+endif
+ifdef BOARD_KERNEL_BASE
+  INTERNAL_RECOVERYIMAGE_ARGS += --base $(BOARD_KERNEL_BASE)
+endif
+BOARD_KERNEL_PAGESIZE := $(strip $(BOARD_KERNEL_PAGESIZE))
+ifdef BOARD_KERNEL_PAGESIZE
+  INTERNAL_RECOVERYIMAGE_ARGS += --pagesize $(BOARD_KERNEL_PAGESIZE)
+endif
+
+# Keys authorized to sign OTA packages this build will accept.  The
+# build always uses test-keys for this; release packaging tools will
+# substitute other keys for this one.
+OTA_PUBLIC_KEYS := $(SRC_TARGET_DIR)/product/security/testkey.x509.pem
+
+# Generate a file containing the keys that will be read by the
+# recovery binary.
+RECOVERY_INSTALL_OTA_KEYS := \
+       $(call intermediates-dir-for,PACKAGING,ota_keys)/keys
+DUMPKEY_JAR := $(HOST_OUT_JAVA_LIBRARIES)/dumpkey.jar
+$(RECOVERY_INSTALL_OTA_KEYS): PRIVATE_OTA_PUBLIC_KEYS := $(OTA_PUBLIC_KEYS)
+$(RECOVERY_INSTALL_OTA_KEYS): $(OTA_PUBLIC_KEYS) $(DUMPKEY_JAR)
+       @echo "DumpPublicKey: $@ <= $(PRIVATE_OTA_PUBLIC_KEYS)"
+       @rm -rf $@
+       @mkdir -p $(dir $@)
+       java -jar $(DUMPKEY_JAR) $(PRIVATE_OTA_PUBLIC_KEYS) > $@
+
+$(INSTALLED_RECOVERYIMAGE_TARGET): $(MKBOOTFS) $(MKBOOTIMG) $(MINIGZIP) \
+               $(INSTALLED_RAMDISK_TARGET) \
+               $(INSTALLED_BOOTIMAGE_TARGET) \
+               $(recovery_binary) \
+               $(recovery_initrc) $(recovery_kernel) \
+               $(INSTALLED_2NDBOOTLOADER_TARGET) \
+               $(recovery_build_prop) $(recovery_resource_deps) \
+               $(recovery_fstab) \
+               $(RECOVERY_INSTALL_OTA_KEYS)
+       @echo ----- Making recovery image ------
+       rm -rf $(TARGET_RECOVERY_OUT)
+       mkdir -p $(TARGET_RECOVERY_OUT)
+       mkdir -p $(TARGET_RECOVERY_ROOT_OUT)
+       mkdir -p $(TARGET_RECOVERY_ROOT_OUT)/etc
+       mkdir -p $(TARGET_RECOVERY_ROOT_OUT)/tmp
+       echo Copying baseline ramdisk...
+       cp -R $(TARGET_ROOT_OUT) $(TARGET_RECOVERY_OUT)
+       rm $(TARGET_RECOVERY_ROOT_OUT)/init*.rc
+       echo Modifying ramdisk contents...
+       cp -f $(recovery_initrc) $(TARGET_RECOVERY_ROOT_OUT)/
+       cp -f $(recovery_binary) $(TARGET_RECOVERY_ROOT_OUT)/sbin/
+       cp -rf $(recovery_resources_common) $(TARGET_RECOVERY_ROOT_OUT)/
+       $(foreach item,$(recovery_resources_private), \
+         cp -rf $(item) $(TARGET_RECOVERY_ROOT_OUT)/)
+       $(foreach item,$(recovery_fstab), \
+         cp -f $(item) $(TARGET_RECOVERY_ROOT_OUT)/etc/recovery.fstab)
+       cp $(RECOVERY_INSTALL_OTA_KEYS) $(TARGET_RECOVERY_ROOT_OUT)/res/keys
+       cat $(INSTALLED_DEFAULT_PROP_TARGET) $(recovery_build_prop) \
+               > $(TARGET_RECOVERY_ROOT_OUT)/default.prop
+       $(MKBOOTFS) $(TARGET_RECOVERY_ROOT_OUT) | $(MINIGZIP) > $(recovery_ramdisk)
+       $(MKBOOTIMG) $(INTERNAL_RECOVERYIMAGE_ARGS) --output $@
+       @echo ----- Made recovery image -------- $@
+       $(hide) $(call assert-max-image-size,$@,$(BOARD_RECOVERYIMAGE_PARTITION_SIZE),raw)
+
+else
+INSTALLED_RECOVERYIMAGE_TARGET :=
+endif
+
+.PHONY: recoveryimage
+recoveryimage: $(INSTALLED_RECOVERYIMAGE_TARGET)
+
+ifneq ($(BOARD_NAND_PAGE_SIZE),)
+mkyaffs2_extra_flags := -c $(BOARD_NAND_PAGE_SIZE)
+else
+mkyaffs2_extra_flags :=
+BOARD_NAND_PAGE_SIZE := 2048
+endif
+
+ifneq ($(BOARD_NAND_SPARE_SIZE),)
+mkyaffs2_extra_flags += -s $(BOARD_NAND_SPARE_SIZE)
+else
+BOARD_NAND_SPARE_SIZE := 64
+endif
+
+# -----------------------------------------------------------------
+# system image
+#
+systemimage_intermediates := \
+       $(call intermediates-dir-for,PACKAGING,systemimage)
+BUILT_SYSTEMIMAGE := $(systemimage_intermediates)/system.img
+
+INTERNAL_SYSTEMIMAGE_FILES := $(filter $(TARGET_OUT)/%, \
+       $(ALL_PREBUILT) \
+       $(ALL_COPIED_HEADERS) \
+       $(ALL_GENERATED_SOURCES) \
+       $(ALL_DEFAULT_INSTALLED_MODULES))
+
+ifeq ($(INTERNAL_USERIMAGES_USE_EXT),true)
+## generate an ext2 image
+# $(1): output file
+define build-systemimage-target
+    @echo "Target system fs image: $(1)"
+    $(call build-userimage-ext-target,$(TARGET_OUT),$(1),system,$(INTERNAL_USERIMAGES_EXT_VARIANT),$(BOARD_SYSTEMIMAGE_PARTITION_SIZE))
+endef
+
+else # INTERNAL_USERIMAGES_USE_EXT != true
+
+## generate a yaffs2 image
+# $(1): output file
+define build-systemimage-target
+    @echo "Target system fs image: $(1)"
+    @mkdir -p $(dir $(1))
+    $(hide) $(MKYAFFS2) -f $(mkyaffs2_extra_flags) $(TARGET_OUT) $(1)
+endef
+endif # INTERNAL_USERIMAGES_USE_EXT
+
+$(BUILT_SYSTEMIMAGE): $(INTERNAL_SYSTEMIMAGE_FILES) $(INTERNAL_USERIMAGES_DEPS)
+       $(call build-systemimage-target,$@)
+
+INSTALLED_SYSTEMIMAGE := $(PRODUCT_OUT)/system.img
+SYSTEMIMAGE_SOURCE_DIR := $(TARGET_OUT)
+
+# The system partition needs room for the recovery image as well.  We
+# now store the recovery image as a binary patch using the boot image
+# as the source (since they are very similar).  Generate the patch so
+# we can see how big it's going to be, and include that in the system
+# image size check calculation.
+ifneq ($(INSTALLED_RECOVERYIMAGE_TARGET),)
+intermediates := $(call intermediates-dir-for,PACKAGING,recovery_patch)
+RECOVERY_FROM_BOOT_PATCH := $(intermediates)/recovery_from_boot.p
+$(RECOVERY_FROM_BOOT_PATCH): $(INSTALLED_RECOVERYIMAGE_TARGET) \
+                             $(INSTALLED_BOOTIMAGE_TARGET) \
+                            $(HOST_OUT_EXECUTABLES)/imgdiff \
+                            $(HOST_OUT_EXECUTABLES)/bsdiff
+       @echo "Construct recovery from boot"
+       mkdir -p $(dir $@)
+       PATH=$(HOST_OUT_EXECUTABLES):$$PATH $(HOST_OUT_EXECUTABLES)/imgdiff $(INSTALLED_BOOTIMAGE_TARGET) $(INSTALLED_RECOVERYIMAGE_TARGET) $@
+endif
+
+
+$(INSTALLED_SYSTEMIMAGE): $(BUILT_SYSTEMIMAGE) $(RECOVERY_FROM_BOOT_PATCH) | $(ACP)
+       @echo "Install system fs image: $@"
+       $(copy-file-to-target)
+       $(hide) $(call assert-max-image-size,$@ $(RECOVERY_FROM_BOOT_PATCH),$(BOARD_SYSTEMIMAGE_PARTITION_SIZE),yaffs)
+
+systemimage: $(INSTALLED_SYSTEMIMAGE)
+
+.PHONY: systemimage-nodeps snod
+systemimage-nodeps snod: $(filter-out systemimage-nodeps snod,$(MAKECMDGOALS)) \
+                   | $(INTERNAL_USERIMAGES_DEPS)
+       @echo "make $@: ignoring dependencies"
+       $(call build-systemimage-target,$(INSTALLED_SYSTEMIMAGE))
+       $(hide) $(call assert-max-image-size,$(INSTALLED_SYSTEMIMAGE),$(BOARD_SYSTEMIMAGE_PARTITION_SIZE),yaffs)
+
+#######
+## system tarball
+define build-systemtarball-target
+    $(call pretty,"Target system fs tarball: $(INSTALLED_SYSTEMTARBALL_TARGET)")
+    $(MKTARBALL) $(FS_GET_STATS) \
+               $(PRODUCT_OUT) system $(PRIVATE_SYSTEM_TAR) \
+               $(INSTALLED_SYSTEMTARBALL_TARGET)
+endef
+
+ifndef SYSTEM_TARBALL_FORMAT
+    SYSTEM_TARBALL_FORMAT := bz2
+endif
+
+system_tar := $(PRODUCT_OUT)/system.tar
+INSTALLED_SYSTEMTARBALL_TARGET := $(system_tar).$(SYSTEM_TARBALL_FORMAT)
+$(INSTALLED_SYSTEMTARBALL_TARGET): PRIVATE_SYSTEM_TAR := $(system_tar)
+$(INSTALLED_SYSTEMTARBALL_TARGET): $(FS_GET_STATS) $(INTERNAL_SYSTEMIMAGE_FILES)
+       $(build-systemtarball-target)
+
+.PHONY: systemtarball-nodeps
+systemtarball-nodeps: $(FS_GET_STATS) \
+                      $(filter-out systemtarball-nodeps stnod,$(MAKECMDGOALS))
+       $(build-systemtarball-target)
+
+.PHONY: stnod
+stnod: systemtarball-nodeps
+
+
+#######
+## boot tarball
+define build-boottarball-target
+    $(hide) echo "Target boot fs tarball: $(INSTALLED_BOOTTARBALL_TARGET)"
+    $(hide) mkdir -p $(PRODUCT_OUT)/boot
+    $(hide) cp -f $(INTERNAL_BOOTIMAGE_FILES) $(PRODUCT_OUT)/boot/.
+    $(hide) echo $(BOARD_KERNEL_CMDLINE) > $(PRODUCT_OUT)/boot/cmdline
+    $(hide) $(MKTARBALL) $(FS_GET_STATS) \
+                 $(PRODUCT_OUT) boot $(PRIVATE_BOOT_TAR) \
+                 $(INSTALLED_BOOTTARBALL_TARGET)
+endef
+
+ifndef BOOT_TARBALL_FORMAT
+    BOOT_TARBALL_FORMAT := bz2
+endif
+
+boot_tar := $(PRODUCT_OUT)/boot.tar
+INSTALLED_BOOTTARBALL_TARGET := $(boot_tar).$(BOOT_TARBALL_FORMAT)
+$(INSTALLED_BOOTTARBALL_TARGET): PRIVATE_BOOT_TAR := $(boot_tar)
+$(INSTALLED_BOOTTARBALL_TARGET): $(FS_GET_STATS) $(INTERNAL_BOOTIMAGE_FILES)
+       $(build-boottarball-target)
+
+.PHONY: boottarball-nodeps btnod
+boottarball-nodeps btnod: $(FS_GET_STATS) \
+                      $(filter-out boottarball-nodeps btnod,$(MAKECMDGOALS))
+       $(build-boottarball-target)
+
+
+# -----------------------------------------------------------------
+# data partition image
+INTERNAL_USERDATAIMAGE_FILES := \
+       $(filter $(TARGET_OUT_DATA)/%,$(ALL_DEFAULT_INSTALLED_MODULES))
+
+ifeq ($(INTERNAL_USERIMAGES_USE_EXT),true)
+## Generate an ext image
+define build-userdataimage-target
+    $(call pretty,"Target userdata fs image: $(INSTALLED_USERDATAIMAGE_TARGET)")
+    @mkdir -p $(TARGET_OUT_DATA)
+    $(call build-userimage-ext-target,$(TARGET_OUT_DATA),$(INSTALLED_USERDATAIMAGE_TARGET),data,$(INTERNAL_USERIMAGES_EXT_VARIANT),$(BOARD_USERDATAIMAGE_PARTITION_SIZE))
+    $(hide) $(call assert-max-image-size,$(INSTALLED_USERDATAIMAGE_TARGET),$(BOARD_USERDATAIMAGE_PARTITION_SIZE),yaffs)
+endef
+
+else # INTERNAL_USERIMAGES_USE_EXT != true
+
+## Generate a yaffs2 image
+define build-userdataimage-target
+    $(call pretty,"Target userdata fs image: $(INSTALLED_USERDATAIMAGE_TARGET)")
+    @mkdir -p $(TARGET_OUT_DATA)
+    $(hide) $(MKYAFFS2) -f $(mkyaffs2_extra_flags) $(TARGET_OUT_DATA) $(INSTALLED_USERDATAIMAGE_TARGET)
+    $(hide) $(call assert-max-image-size,$(INSTALLED_USERDATAIMAGE_TARGET),$(BOARD_USERDATAIMAGE_PARTITION_SIZE),yaffs)
+endef
+endif # INTERNAL_USERIMAGES_USE_EXT
+
+BUILT_USERDATAIMAGE_TARGET := $(PRODUCT_OUT)/userdata.img
+
+# We just build this directly to the install location.
+INSTALLED_USERDATAIMAGE_TARGET := $(BUILT_USERDATAIMAGE_TARGET)
+$(INSTALLED_USERDATAIMAGE_TARGET): $(INTERNAL_USERIMAGES_DEPS) \
+                                   $(INTERNAL_USERDATAIMAGE_FILES)
+       $(build-userdataimage-target)
+
+.PHONY: userdataimage-nodeps
+userdataimage-nodeps: $(INTERNAL_USERIMAGES_DEPS)
+       $(build-userdataimage-target)
+
+#######
+## data partition tarball
+define build-userdatatarball-target
+    $(call pretty,"Target userdata fs tarball: " \
+                  "$(INSTALLED_USERDATATARBALL_TARGET)")
+    $(MKTARBALL) $(FS_GET_STATS) \
+               $(PRODUCT_OUT) data $(PRIVATE_USERDATA_TAR) \
+               $(INSTALLED_USERDATATARBALL_TARGET)
+endef
+
+userdata_tar := $(PRODUCT_OUT)/userdata.tar
+INSTALLED_USERDATATARBALL_TARGET := $(userdata_tar).bz2
+$(INSTALLED_USERDATATARBALL_TARGET): PRIVATE_USERDATA_TAR := $(userdata_tar)
+$(INSTALLED_USERDATATARBALL_TARGET): $(FS_GET_STATS) $(INTERNAL_USERDATAIMAGE_FILES)
+       $(build-userdatatarball-target)
+
+.PHONY: userdatatarball-nodeps
+userdatatarball-nodeps: $(FS_GET_STATS)
+       $(build-userdatatarball-target)
+
+
+# -----------------------------------------------------------------
+# bring in the installer image generation defines if necessary
+ifeq ($(TARGET_USE_DISKINSTALLER),true)
+include bootable/diskinstaller/config.mk
+endif
+
+# -----------------------------------------------------------------
+# host tools needed to build OTA packages
+
+OTATOOLS :=  $(HOST_OUT_EXECUTABLES)/minigzip \
+         $(HOST_OUT_EXECUTABLES)/mkbootfs \
+         $(HOST_OUT_EXECUTABLES)/mkbootimg \
+         $(HOST_OUT_EXECUTABLES)/fs_config \
+         $(HOST_OUT_EXECUTABLES)/mkyaffs2image \
+         $(HOST_OUT_EXECUTABLES)/zipalign \
+         $(HOST_OUT_EXECUTABLES)/aapt \
+         $(HOST_OUT_EXECUTABLES)/bsdiff \
+         $(HOST_OUT_EXECUTABLES)/imgdiff \
+         $(HOST_OUT_JAVA_LIBRARIES)/dumpkey.jar \
+         $(HOST_OUT_JAVA_LIBRARIES)/signapk.jar
+
+.PHONY: otatools
+otatools: $(OTATOOLS)
+
+# -----------------------------------------------------------------
+# A zip of the directories that map to the target filesystem.
+# This zip can be used to create an OTA package or filesystem image
+# as a post-build step.
+#
+name := $(TARGET_PRODUCT)
+ifeq ($(TARGET_BUILD_TYPE),debug)
+  name := $(name)_debug
+endif
+name := $(name)-target_files-$(FILE_NAME_TAG)
+
+intermediates := $(call intermediates-dir-for,PACKAGING,target_files)
+BUILT_TARGET_FILES_PACKAGE := $(intermediates)/$(name).zip
+$(BUILT_TARGET_FILES_PACKAGE): intermediates := $(intermediates)
+$(BUILT_TARGET_FILES_PACKAGE): \
+               zip_root := $(intermediates)/$(name)
+
+# $(1): Directory to copy
+# $(2): Location to copy it to
+# The "ls -A" is to prevent "acp s/* d" from failing if s is empty.
+define package_files-copy-root
+  if [ -d "$(strip $(1))" -a "$$(ls -A $(1))" ]; then \
+    mkdir -p $(2) && \
+    $(ACP) -rd $(strip $(1))/* $(2); \
+  fi
+endef
+
+built_ota_tools := \
+       $(call intermediates-dir-for,EXECUTABLES,applypatch)/applypatch \
+       $(call intermediates-dir-for,EXECUTABLES,applypatch_static)/applypatch_static \
+       $(call intermediates-dir-for,EXECUTABLES,check_prereq)/check_prereq \
+       $(call intermediates-dir-for,EXECUTABLES,updater)/updater
+$(BUILT_TARGET_FILES_PACKAGE): PRIVATE_OTA_TOOLS := $(built_ota_tools)
+
+$(BUILT_TARGET_FILES_PACKAGE): PRIVATE_RECOVERY_API_VERSION := $(RECOVERY_API_VERSION)
+
+ifeq ($(TARGET_RELEASETOOLS_EXTENSIONS),)
+# default to common dir for device vendor
+$(BUILT_TARGET_FILES_PACKAGE): tool_extensions := $(TARGET_DEVICE_DIR)/../common
+else
+$(BUILT_TARGET_FILES_PACKAGE): tool_extensions := $(TARGET_RELEASETOOLS_EXTENSIONS)
+endif
+
+# Depending on the various images guarantees that the underlying
+# directories are up-to-date.
+$(BUILT_TARGET_FILES_PACKAGE): \
+               $(INSTALLED_BOOTIMAGE_TARGET) \
+               $(INSTALLED_RADIOIMAGE_TARGET) \
+               $(INSTALLED_RECOVERYIMAGE_TARGET) \
+               $(INSTALLED_SYSTEMIMAGE) \
+               $(INSTALLED_USERDATAIMAGE_TARGET) \
+               $(INSTALLED_ANDROID_INFO_TXT_TARGET) \
+               $(built_ota_tools) \
+               $(APKCERTS_FILE) \
+               $(HOST_OUT_EXECUTABLES)/fs_config \
+               | $(ACP)
+       @echo "Package target files: $@"
+       $(hide) rm -rf $@ $(zip_root)
+       $(hide) mkdir -p $(dir $@) $(zip_root)
+       @# Components of the recovery image
+       $(hide) mkdir -p $(zip_root)/RECOVERY
+       $(hide) $(call package_files-copy-root, \
+               $(TARGET_RECOVERY_ROOT_OUT),$(zip_root)/RECOVERY/RAMDISK)
+ifdef INSTALLED_KERNEL_TARGET
+       $(hide) $(ACP) $(INSTALLED_KERNEL_TARGET) $(zip_root)/RECOVERY/kernel
+endif
+ifdef INSTALLED_2NDBOOTLOADER_TARGET
+       $(hide) $(ACP) \
+               $(INSTALLED_2NDBOOTLOADER_TARGET) $(zip_root)/RECOVERY/second
+endif
+ifdef BOARD_KERNEL_CMDLINE
+       $(hide) echo "$(BOARD_KERNEL_CMDLINE)" > $(zip_root)/RECOVERY/cmdline
+endif
+ifdef BOARD_KERNEL_BASE
+       $(hide) echo "$(BOARD_KERNEL_BASE)" > $(zip_root)/RECOVERY/base
+endif
+ifdef BOARD_KERNEL_PAGESIZE
+       $(hide) echo "$(BOARD_KERNEL_PAGESIZE)" > $(zip_root)/RECOVERY/pagesize
+endif
+       @# Components of the boot image
+       $(hide) mkdir -p $(zip_root)/BOOT
+       $(hide) $(call package_files-copy-root, \
+               $(TARGET_ROOT_OUT),$(zip_root)/BOOT/RAMDISK)
+ifdef INSTALLED_KERNEL_TARGET
+       $(hide) $(ACP) $(INSTALLED_KERNEL_TARGET) $(zip_root)/BOOT/kernel
+endif
+ifdef INSTALLED_2NDBOOTLOADER_TARGET
+       $(hide) $(ACP) \
+               $(INSTALLED_2NDBOOTLOADER_TARGET) $(zip_root)/BOOT/second
+endif
+ifdef BOARD_KERNEL_CMDLINE
+       $(hide) echo "$(BOARD_KERNEL_CMDLINE)" > $(zip_root)/BOOT/cmdline
+endif
+ifdef BOARD_KERNEL_BASE
+       $(hide) echo "$(BOARD_KERNEL_BASE)" > $(zip_root)/BOOT/base
+endif
+ifdef BOARD_KERNEL_PAGESIZE
+       $(hide) echo "$(BOARD_KERNEL_PAGESIZE)" > $(zip_root)/BOOT/pagesize
+endif
+       $(hide) $(foreach t,$(INSTALLED_RADIOIMAGE_TARGET),\
+                   mkdir -p $(zip_root)/RADIO; \
+                   $(ACP) $(t) $(zip_root)/RADIO/$(notdir $(t));)
+       @# Contents of the system image
+       $(hide) $(call package_files-copy-root, \
+               $(SYSTEMIMAGE_SOURCE_DIR),$(zip_root)/SYSTEM)
+       @# Contents of the data image
+       $(hide) $(call package_files-copy-root, \
+               $(TARGET_OUT_DATA),$(zip_root)/DATA)
+       @# Extra contents of the OTA package
+       $(hide) mkdir -p $(zip_root)/OTA/bin
+       $(hide) $(ACP) $(INSTALLED_ANDROID_INFO_TXT_TARGET) $(zip_root)/OTA/
+       $(hide) $(ACP) $(PRIVATE_OTA_TOOLS) $(zip_root)/OTA/bin/
+       @# Files that do not end up in any images, but are necessary to
+       @# build them.
+       $(hide) mkdir -p $(zip_root)/META
+       $(hide) $(ACP) $(APKCERTS_FILE) $(zip_root)/META/apkcerts.txt
+       $(hide) echo "$(PRODUCT_OTA_PUBLIC_KEYS)" > $(zip_root)/META/otakeys.txt
+       $(hide) echo "recovery_api_version=$(PRIVATE_RECOVERY_API_VERSION)" > $(zip_root)/META/misc_info.txt
+ifdef BOARD_FLASH_BLOCK_SIZE
+       $(hide) echo "blocksize=$(BOARD_FLASH_BLOCK_SIZE)" >> $(zip_root)/META/misc_info.txt
+endif
+ifdef BOARD_BOOTIMAGE_PARTITION_SIZE
+       $(hide) echo "boot_size=$(BOARD_BOOTIMAGE_PARTITION_SIZE)" >> $(zip_root)/META/misc_info.txt
+endif
+ifdef BOARD_RECOVERYIMAGE_PARTITION_SIZE
+       $(hide) echo "recovery_size=$(BOARD_RECOVERYIMAGE_PARTITION_SIZE)" >> $(zip_root)/META/misc_info.txt
+endif
+ifdef BOARD_SYSTEMIMAGE_PARTITION_SIZE
+       $(hide) echo "system_size=$(BOARD_SYSTEMIMAGE_PARTITION_SIZE)" >> $(zip_root)/META/misc_info.txt
+endif
+ifdef BOARD_USERDATAIMAGE_PARTITION_SIZE
+       $(hide) echo "userdata_size=$(BOARD_USERDATAIMAGE_PARTITION_SIZE)" >> $(zip_root)/META/misc_info.txt
+endif
+       $(hide) echo "tool_extensions=$(tool_extensions)" >> $(zip_root)/META/misc_info.txt
+ifdef mkyaffs2_extra_flags
+       $(hide) echo "mkyaffs2_extra_flags=$(mkyaffs2_extra_flags)" >> $(zip_root)/META/misc_info.txt
+endif
+ifdef INTERNAL_USERIMAGES_SPARSE_EXT_FLAG
+       $(hide) echo "extfs_sparse_flag=$(INTERNAL_USERIMAGES_SPARSE_EXT_FLAG)" >> $(zip_root)/META/misc_info.txt
+endif
+       @# Zip everything up, preserving symlinks
+       $(hide) (cd $(zip_root) && zip -qry ../$(notdir $@) .)
+       @# Run fs_config on all the system files in the zip, and save the output
+       $(hide) zipinfo -1 $@ | awk -F/ 'BEGIN { OFS="/" } /^SYSTEM\// {$$1 = "system"; print}' | $(HOST_OUT_EXECUTABLES)/fs_config > $(zip_root)/META/filesystem_config.txt
+       $(hide) (cd $(zip_root) && zip -q ../$(notdir $@) META/filesystem_config.txt)
+
+
+target-files-package: $(BUILT_TARGET_FILES_PACKAGE)
+
+
+ifneq ($(TARGET_SIMULATOR),true)
+ifneq ($(TARGET_PRODUCT),sdk)
+ifneq ($(TARGET_DEVICE),generic)
+ifneq ($(TARGET_NO_KERNEL),true)
+
+# -----------------------------------------------------------------
+# OTA update package
+
+name := $(TARGET_PRODUCT)
+ifeq ($(TARGET_BUILD_TYPE),debug)
+  name := $(name)_debug
+endif
+name := $(name)-ota-$(FILE_NAME_TAG)
+
+INTERNAL_OTA_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name).zip
+
+$(INTERNAL_OTA_PACKAGE_TARGET): KEY_CERT_PAIR := $(DEFAULT_KEY_CERT_PAIR)
+
+$(INTERNAL_OTA_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(OTATOOLS)
+       @echo "Package OTA: $@"
+       $(hide) ./build/tools/releasetools/ota_from_target_files -v \
+          -p $(HOST_OUT) \
+           -k $(KEY_CERT_PAIR) \
+           $(BUILT_TARGET_FILES_PACKAGE) $@
+
+.PHONY: otapackage
+otapackage: $(INTERNAL_OTA_PACKAGE_TARGET)
+
+# -----------------------------------------------------------------
+# The update package
+
+name := $(TARGET_PRODUCT)
+ifeq ($(TARGET_BUILD_TYPE),debug)
+  name := $(name)_debug
+endif
+name := $(name)-img-$(FILE_NAME_TAG)
+
+INTERNAL_UPDATE_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name).zip
+
+ifeq ($(TARGET_RELEASETOOLS_EXTENSIONS),)
+# default to common dir for device vendor
+$(INTERNAL_UPDATE_PACKAGE_TARGET): extensions := $(TARGET_DEVICE_DIR)/../common
+else
+$(INTERNAL_UPDATE_PACKAGE_TARGET): extensions := $(TARGET_RELEASETOOLS_EXTENSIONS)
+endif
+
+$(INTERNAL_UPDATE_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(OTATOOLS)
+       @echo "Package: $@"
+       $(hide) ./build/tools/releasetools/img_from_target_files -v \
+          -s $(extensions) \
+          -p $(HOST_OUT) \
+          $(BUILT_TARGET_FILES_PACKAGE) $@
+
+.PHONY: updatepackage
+updatepackage: $(INTERNAL_UPDATE_PACKAGE_TARGET)
+
+endif    # TARGET_NO_KERNEL != true
+endif    # TARGET_DEVICE != generic
+endif    # TARGET_PRODUCT != sdk
+endif    # TARGET_SIMULATOR != true
+
+# -----------------------------------------------------------------
+# installed file list
+# Depending on $(INSTALLED_SYSTEMIMAGE) ensures that it
+# gets the DexOpt one if we're doing that.
+INSTALLED_FILES_FILE := $(PRODUCT_OUT)/installed-files.txt
+$(INSTALLED_FILES_FILE): $(INSTALLED_SYSTEMIMAGE)
+       @echo Installed file list: $@
+       @mkdir -p $(dir $@)
+       @rm -f $@
+       $(hide) build/tools/fileslist.py $(TARGET_OUT) $(TARGET_OUT_DATA) > $@
+
+.PHONY: installed-file-list
+installed-file-list: $(INSTALLED_FILES_FILE)
+$(call dist-for-goals, sdk, $(INSTALLED_FILES_FILE))
+$(call dist-for-goals, sdk_addon, $(INSTALLED_FILES_FILE))
+
+# -----------------------------------------------------------------
+# A zip of the tests that are built when running "make tests".
+# This is very similar to BUILT_TARGET_FILES_PACKAGE, but we
+# only grab SYSTEM and DATA, and it's called "*-tests-*.zip".
+#
+name := $(TARGET_PRODUCT)
+ifeq ($(TARGET_BUILD_TYPE),debug)
+  name := $(name)_debug
+endif
+name := $(name)-tests-$(FILE_NAME_TAG)
+
+intermediates := $(call intermediates-dir-for,PACKAGING,tests_zip)
+BUILT_TESTS_ZIP_PACKAGE := $(intermediates)/$(name).zip
+$(BUILT_TESTS_ZIP_PACKAGE): intermediates := $(intermediates)
+$(BUILT_TESTS_ZIP_PACKAGE): zip_root := $(intermediates)/$(name)
+
+# Depending on the images guarantees that the underlying
+# directories are up-to-date.
+$(BUILT_TESTS_ZIP_PACKAGE): \
+               $(BUILT_SYSTEMIMAGE) \
+               $(INSTALLED_USERDATAIMAGE_TARGET) \
+               | $(ACP)
+       @echo "Package test files: $@"
+       $(hide) rm -rf $@ $(zip_root)
+       $(hide) mkdir -p $(dir $@) $(zip_root)
+       @# Some parts of the system image
+       $(hide) $(call package_files-copy-root, \
+               $(SYSTEMIMAGE_SOURCE_DIR)/xbin,$(zip_root)/SYSTEM/xbin)
+       $(hide) $(call package_files-copy-root, \
+               $(SYSTEMIMAGE_SOURCE_DIR)/lib,$(zip_root)/SYSTEM/lib)
+       $(hide) $(call package_files-copy-root, \
+               $(SYSTEMIMAGE_SOURCE_DIR)/framework, \
+               $(zip_root)/SYSTEM/framework)
+       $(hide) $(ACP) $(SYSTEMIMAGE_SOURCE_DIR)/build.prop $(zip_root)/SYSTEM
+       @# Contents of the data image
+       $(hide) $(call package_files-copy-root, \
+               $(TARGET_OUT_DATA),$(zip_root)/DATA)
+       $(hide) (cd $(zip_root) && zip -qry ../$(notdir $@) .)
+
+.PHONY: tests-zip-package
+tests-zip-package: $(BUILT_TESTS_ZIP_PACKAGE)
+
+# Target needed by tests build
+.PHONY: tests-build-target
+tests-build-target: $(BUILT_TESTS_ZIP_PACKAGE) \
+                    $(BUILT_USERDATAIMAGE_TARGET)
+
+ifneq (,$(filter $(MAKECMDGOALS),tests-build-target))
+  $(call dist-for-goals, tests-build-target, \
+          $(BUILT_TESTS_ZIP_PACKAGE) \
+          $(BUILT_USERDATAIMAGE_TARGET))
+endif
+
+# -----------------------------------------------------------------
+# A zip of the symbols directory.  Keep the full paths to make it
+# more obvious where these files came from.
+#
+name := $(TARGET_PRODUCT)
+ifeq ($(TARGET_BUILD_TYPE),debug)
+  name := $(name)_debug
+endif
+name := $(name)-symbols-$(FILE_NAME_TAG)
+
+SYMBOLS_ZIP := $(PRODUCT_OUT)/$(name).zip
+$(SYMBOLS_ZIP): $(INSTALLED_SYSTEMIMAGE) $(INSTALLED_BOOTIMAGE_TARGET)
+       @echo "Package symbols: $@"
+       $(hide) rm -rf $@
+       $(hide) mkdir -p $(dir $@)
+       $(hide) zip -qr $@ $(TARGET_OUT_UNSTRIPPED)
+
+# -----------------------------------------------------------------
+# A zip of the Android Apps. Not keeping full path so that we don't
+# include product names when distributing
+#
+name := $(TARGET_PRODUCT)
+ifeq ($(TARGET_BUILD_TYPE),debug)
+  name := $(name)_debug
+endif
+name := $(name)-apps-$(FILE_NAME_TAG)
+
+APPS_ZIP := $(PRODUCT_OUT)/$(name).zip
+$(APPS_ZIP): $(INSTALLED_SYSTEMIMAGE)
+       @echo "Package apps: $@"
+       $(hide) rm -rf $@
+       $(hide) mkdir -p $(dir $@)
+       $(hide) zip -qj $@ $(TARGET_OUT_APPS)/*
+
+
+#------------------------------------------------------------------
+# A zip of emma code coverage meta files. Generated for fully emma
+# instrumented build.
+#
+EMMA_META_ZIP := $(PRODUCT_OUT)/emma_meta.zip
+$(EMMA_META_ZIP): $(INSTALLED_SYSTEMIMAGE)
+       @echo "Collecting Emma coverage meta files."
+       $(hide) find $(TARGET_COMMON_OUT_ROOT) -name "coverage.em" | \
+               zip -@ -q $@
+
+endif  # TARGET_SIMULATOR != true
+
+# -----------------------------------------------------------------
+# dalvik something
+.PHONY: dalvikfiles
+dalvikfiles: $(INTERNAL_DALVIK_MODULES)
+
+# -----------------------------------------------------------------
+# The emulator package
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+INTERNAL_EMULATOR_PACKAGE_FILES += \
+        $(HOST_OUT_EXECUTABLES)/emulator$(HOST_EXECUTABLE_SUFFIX) \
+        prebuilt/android-arm/kernel/kernel-qemu \
+        $(INSTALLED_RAMDISK_TARGET) \
+               $(INSTALLED_SYSTEMIMAGE) \
+               $(INSTALLED_USERDATAIMAGE_TARGET)
+
+name := $(TARGET_PRODUCT)-emulator-$(FILE_NAME_TAG)
+
+INTERNAL_EMULATOR_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name).zip
+
+$(INTERNAL_EMULATOR_PACKAGE_TARGET): $(INTERNAL_EMULATOR_PACKAGE_FILES)
+       @echo "Package: $@"
+       $(hide) zip -qj $@ $(INTERNAL_EMULATOR_PACKAGE_FILES)
+
+endif
+
+# -----------------------------------------------------------------
+# The pdk package (Platform Development Kit)
+
+ifneq (,$(filter pdk,$(MAKECMDGOALS)))
+  include development/pdk/Pdk.mk
+endif
+
+# -----------------------------------------------------------------
+# The SDK
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+# The SDK includes host-specific components, so it belongs under HOST_OUT.
+sdk_dir := $(HOST_OUT)/sdk
+
+# Build a name that looks like:
+#
+#     linux-x86   --> android-sdk_12345_linux-x86
+#     darwin-x86  --> android-sdk_12345_mac-x86
+#     windows-x86 --> android-sdk_12345_windows
+#
+sdk_name := android-sdk_$(FILE_NAME_TAG)
+ifeq ($(HOST_OS),darwin)
+  INTERNAL_SDK_HOST_OS_NAME := mac
+else
+  INTERNAL_SDK_HOST_OS_NAME := $(HOST_OS)
+endif
+ifneq ($(HOST_OS),windows)
+  INTERNAL_SDK_HOST_OS_NAME := $(INTERNAL_SDK_HOST_OS_NAME)-$(HOST_ARCH)
+endif
+sdk_name := $(sdk_name)_$(INTERNAL_SDK_HOST_OS_NAME)
+
+sdk_dep_file := $(sdk_dir)/sdk_deps.mk
+
+ATREE_FILES :=
+-include $(sdk_dep_file)
+
+# if we don't have a real list, then use "everything"
+ifeq ($(strip $(ATREE_FILES)),)
+ATREE_FILES := \
+       $(ALL_PREBUILT) \
+       $(ALL_COPIED_HEADERS) \
+       $(ALL_GENERATED_SOURCES) \
+       $(ALL_DEFAULT_INSTALLED_MODULES) \
+       $(INSTALLED_RAMDISK_TARGET) \
+       $(ALL_DOCS) \
+       $(ALL_SDK_FILES)
+endif
+
+atree_dir := development/build
+
+sdk_atree_files := \
+       $(atree_dir)/sdk.exclude.atree \
+       $(atree_dir)/sdk.atree \
+       $(atree_dir)/sdk-$(HOST_OS)-$(HOST_ARCH).atree \
+       sdk/build/tools.atree
+
+deps := \
+       $(target_notice_file_txt) \
+       $(tools_notice_file_txt) \
+       $(OUT_DOCS)/offline-sdk-timestamp \
+       $(SYMBOLS_ZIP) \
+       $(INSTALLED_SYSTEMIMAGE) \
+       $(INSTALLED_USERDATAIMAGE_TARGET) \
+       $(INSTALLED_RAMDISK_TARGET) \
+       $(INSTALLED_SDK_BUILD_PROP_TARGET) \
+       $(INSTALLED_BUILD_PROP_TARGET) \
+       $(ATREE_FILES) \
+       $(atree_dir)/sdk.atree \
+       sdk/build/tools.atree \
+       $(HOST_OUT_EXECUTABLES)/atree \
+    $(HOST_OUT_EXECUTABLES)/line_endings
+
+INTERNAL_SDK_TARGET := $(sdk_dir)/$(sdk_name).zip
+$(INTERNAL_SDK_TARGET): PRIVATE_NAME := $(sdk_name)
+$(INTERNAL_SDK_TARGET): PRIVATE_DIR := $(sdk_dir)/$(sdk_name)
+$(INTERNAL_SDK_TARGET): PRIVATE_DEP_FILE := $(sdk_dep_file)
+$(INTERNAL_SDK_TARGET): PRIVATE_INPUT_FILES := $(sdk_atree_files)
+
+# Set SDK_GNU_ERROR to non-empty to fail when a GNU target is built.
+#
+#SDK_GNU_ERROR := true
+
+ifeq ($(HOST_OS),darwin)
+HOST_STRIP_SDK_LLVM := strip
+else
+HOST_STRIP_SDK_LLVM := strip --strip-all
+endif
+
+$(INTERNAL_SDK_TARGET): $(deps)
+       @echo "Package SDK: $@"
+       $(hide) rm -rf $(PRIVATE_DIR) $@
+       $(hide) for f in $(target_gnu_MODULES); do \
+         if [ -f $$f ]; then \
+           echo SDK: $(if $(SDK_GNU_ERROR),ERROR:,warning:) \
+               including GNU target $$f >&2; \
+           FAIL=$(SDK_GNU_ERROR); \
+         fi; \
+       done; \
+       if [ $$FAIL ]; then exit 1; fi
+       $(hide) ( \
+               $(HOST_OUT_EXECUTABLES)/atree \
+               $(addprefix -f ,$(PRIVATE_INPUT_FILES)) \
+                       -m $(PRIVATE_DEP_FILE) \
+                       -I . \
+                       -I $(PRODUCT_OUT) \
+                       -I $(HOST_OUT) \
+                       -I $(TARGET_COMMON_OUT_ROOT) \
+                       -v "PLATFORM_NAME=android-$(PLATFORM_VERSION)" \
+                       -v "OUT_DIR=$(OUT_DIR)" \
+                       -o $(PRIVATE_DIR) && \
+               cp -f $(target_notice_file_txt) \
+                               $(PRIVATE_DIR)/platforms/android-$(PLATFORM_VERSION)/images/NOTICE.txt && \
+               cp -f $(tools_notice_file_txt) $(PRIVATE_DIR)/tools/NOTICE.txt && \
+               if [ -f $(PRIVATE_DIR)/platform-tools/llvm-rs-cc ]; then \
+                       $(HOST_STRIP_SDK_LLVM) $(PRIVATE_DIR)/platform-tools/llvm-rs-cc; \
+               fi && \
+               HOST_OUT_EXECUTABLES=$(HOST_OUT_EXECUTABLES) HOST_OS=$(HOST_OS) \
+                       development/build/tools/sdk_clean.sh $(PRIVATE_DIR) && \
+               chmod -R ug+rwX $(PRIVATE_DIR) && \
+               cd $(dir $@) && zip -rq $(notdir $@) $(PRIVATE_NAME) \
+       ) || ( rm -rf $(PRIVATE_DIR) $@ && exit 44 )
+
+
+# Is a Windows SDK requested? If so, we need some definitions from here
+# in order to find the Linux SDK used to create the Windows one.
+ifneq ($(filter win_sdk,$(MAKECMDGOALS)),)
+LINUX_SDK_NAME := $(sdk_name)
+LINUX_SDK_DIR  := $(sdk_dir)
+include $(TOPDIR)development/build/tools/windows_sdk.mk
+endif
+
+endif # !simulator
+
+# -----------------------------------------------------------------
+# Findbugs
+INTERNAL_FINDBUGS_XML_TARGET := $(PRODUCT_OUT)/findbugs.xml
+INTERNAL_FINDBUGS_HTML_TARGET := $(PRODUCT_OUT)/findbugs.html
+$(INTERNAL_FINDBUGS_XML_TARGET): $(ALL_FINDBUGS_FILES)
+       @echo UnionBugs: $@
+       $(hide) prebuilt/common/findbugs/bin/unionBugs $(ALL_FINDBUGS_FILES) \
+       > $@
+$(INTERNAL_FINDBUGS_HTML_TARGET): $(INTERNAL_FINDBUGS_XML_TARGET)
+       @echo ConvertXmlToText: $@
+       $(hide) prebuilt/common/findbugs/bin/convertXmlToText -html:fancy.xsl \
+       $(INTERNAL_FINDBUGS_XML_TARGET) > $@
+
+# -----------------------------------------------------------------
+# Findbugs
+
+# -----------------------------------------------------------------
+# These are some additional build tasks that need to be run.
+include $(sort $(wildcard $(BUILD_SYSTEM)/tasks/*.mk))
+-include $(sort $(wildcard vendor/*/build/tasks/*.mk))
diff --git a/build/core/apicheck_msg_current.txt b/build/core/apicheck_msg_current.txt
new file mode 100644 (file)
index 0000000..5d3a913
--- /dev/null
@@ -0,0 +1,17 @@
+
+******************************
+You have tried to change the API from what has been previously approved.
+
+To make these errors go away, you have two choices:
+   1) You can add "@hide" javadoc comments to the methods, etc. listed in the
+      errors above.
+
+   2) You can update current.xml by executing the following command:
+         make update-api
+
+      To submit the revised current.xml to the main Android repository,
+      you will need approval.
+******************************
+
+
+
diff --git a/build/core/apicheck_msg_last.txt b/build/core/apicheck_msg_last.txt
new file mode 100644 (file)
index 0000000..2993157
--- /dev/null
@@ -0,0 +1,7 @@
+
+******************************
+You have tried to change the API from what has been previously released in
+an SDK.  Please fix the errors listed above.
+******************************
+
+
diff --git a/build/core/armelf.x b/build/core/armelf.x
new file mode 100644 (file)
index 0000000..d38dc1d
--- /dev/null
@@ -0,0 +1,204 @@
+/* Default linker script, for normal executables */
+OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
+             "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SEARCH_DIR("/usr/local/armdev/arm-elf/lib");
+/* Do we need any of these for elf?
+   __DYNAMIC = 0;    */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+/*  PROVIDE (__executable_start = 0x8000); . = 0x8000; */
+. = 0x8000 + SIZEOF_HEADERS; 
+  .interp         : { *(.interp) }
+  .hash           : { *(.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+  .rel.init       : { *(.rel.init) }
+  .rela.init      : { *(.rela.init) }
+  .rel.text       : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
+  .rela.text      : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
+  .rel.fini       : { *(.rel.fini) }
+  .rela.fini      : { *(.rela.fini) }
+  .rel.rodata     : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
+  .rela.rodata    : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
+  .rel.data.rel.ro   : { *(.rel.data.rel.ro*) }
+  .rela.data.rel.ro   : { *(.rel.data.rel.ro*) }
+  .rel.data       : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
+  .rela.data      : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
+  .rel.tdata     : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+  .rela.tdata    : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+  .rel.tbss      : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+  .rela.tbss     : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+  .rel.ctors      : { *(.rel.ctors) }
+  .rela.ctors     : { *(.rela.ctors) }
+  .rel.dtors      : { *(.rel.dtors) }
+  .rela.dtors     : { *(.rela.dtors) }
+  .rel.got        : { *(.rel.got) }
+  .rela.got       : { *(.rela.got) }
+  .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
+  .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
+  .rel.plt        : { *(.rel.plt) }
+  .rela.plt       : { *(.rela.plt) }
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0
+  .plt            : { *(.plt) }
+  .text           :
+  {
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    KEEP (*(.text.*personality*))
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.glue_7t) *(.glue_7)
+  } =0
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  /* We have to wrap extab and exidx sections with KEEP because we use
+     --gc-sections. */
+  .ARM.extab   : { KEEP (*(.ARM.extab* .gnu.linkonce.armextab.*)) }
+   __exidx_start = .;
+  .ARM.exidx   : { KEEP (*(.ARM.exidx* .gnu.linkonce.armexidx.*)) }
+   __exidx_end = .;
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : ONLY_IF_RO { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) }
+  /* Adjust the address for the data segment.  We want to align at exactly
+     a page boundary to make life easier for apriori. */
+  . = ALIGN(4096);
+  /* Exception handling  */
+  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : ONLY_IF_RW { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) }
+  /* Thread Local Storage sections  */
+  .tdata         : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss                  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  /* Ensure the __preinit_array_start label is properly aligned.  We
+     could instead move the label definition inside the section, but
+     the linker would then create the section even if it turns out to
+     be empty, which isn't pretty.  */
+  . = ALIGN(32 / 8);
+  PROVIDE (__preinit_array_start = .);
+  .preinit_array     : { KEEP (*(.preinit_array)) }
+  PROVIDE (__preinit_array_end = .);
+  PROVIDE (__init_array_start = .);
+  .init_array     : { KEEP (*(.init_array)) }
+  PROVIDE (__init_array_end = .);
+  PROVIDE (__fini_array_start = .);
+  .fini_array     : { KEEP (*(.fini_array)) }
+  PROVIDE (__fini_array_end = .);
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin*.o(.ctors))
+    /* We don't want to include the .ctor section from
+       from the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin*.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) }
+  .dynamic        : { *(.dynamic) }
+  .got            : { *(.got.plt) *(.got) }
+  .data           :
+  {
+    __data_start = . ;
+    *(.data .data.* .gnu.linkonce.d.*)
+    KEEP (*(.gnu.linkonce.d.*personality*))
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  _edata = .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  __bss_start__ = .;
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.  */
+   . = ALIGN(32 / 8);
+  }
+  . = ALIGN(32 / 8);
+  _end = .;
+  _bss_end__ = . ; __bss_end__ = . ; __end__ = . ;
+  PROVIDE (end = .);
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* Adding the word ABSOLUTE below, so that the _stack below won't float 
+     into a random section. If _stack is not absolutely with .stack section,
+     we saw that sometimes _stack got inserted into the .debug_frame section
+     because it's processed by the linker at that moment. As a result, _stack
+     symbol will get wrongly moved and gelf_update_symshndx() will return
+     invalid data. */
+    .stack         0x80000 :
+  {
+    _stack = ABSOLUTE(.);
+    *(.stack)
+  }
+  .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
+  /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/build/core/armelf.xsc b/build/core/armelf.xsc
new file mode 100644 (file)
index 0000000..9fac3d2
--- /dev/null
@@ -0,0 +1,207 @@
+/* Script for --shared -z combreloc: shared library, combine & sort relocs */
+OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
+             "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = 0 + SIZEOF_HEADERS;
+  .hash           : { *(.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+  .rel.dyn        :
+    {
+      *(.rel.init)
+      *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+      *(.rel.fini)
+      *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+      *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*)
+      *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+      *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+      *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+      *(.rel.ctors)
+      *(.rel.dtors)
+      *(.rel.got)
+      *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+    }
+  .rela.dyn       :
+    {
+      *(.rela.init)
+      *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+      *(.rela.fini)
+      *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+      *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+      *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+      *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+      *(.rela.ctors)
+      *(.rela.dtors)
+      *(.rela.got)
+      *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+    }
+  .rel.plt        : { *(.rel.plt) }
+  .rela.plt       : { *(.rela.plt) }
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0
+  .plt            : { *(.plt) }
+  .text           :
+  {
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    KEEP (*(.text.*personality*))
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.glue_7t) *(.glue_7)
+  } =0
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  /* We have to wrap extab and exidx sections with KEEP because we use
+     --gc-sections. */
+  .ARM.extab   : { KEEP (*(.ARM.extab* .gnu.linkonce.armextab.*)) }
+   __exidx_start = .;
+  .ARM.exidx   : { KEEP (*(.ARM.exidx* .gnu.linkonce.armexidx.*)) }
+   __exidx_end = .;
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
+  /* Adjust the address for the data segment.  We want to align at exactly
+     a page boundary to make life easier for apriori. */
+  . = ALIGN(4096);
+  /* Exception handling  */
+  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+  /* Thread Local Storage sections  */
+  .tdata         : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss                  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .preinit_array     :
+  {
+    KEEP (*(.preinit_array))
+  }
+  .init_array     :
+  {
+     KEEP (*(SORT(.init_array.*)))
+     KEEP (*(.init_array))
+  }
+  .fini_array     :
+  {
+    KEEP (*(.fini_array))
+    KEEP (*(SORT(.fini_array.*)))
+  }
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin*.o(.ctors))
+    /* We don't want to include the .ctor section from
+       the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin*.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+  .dynamic        : { *(.dynamic) }
+  .got            : { *(.got.plt) *(.got) }
+  .data           :
+  {
+    __data_start = . ;
+    *(.data .data.* .gnu.linkonce.d.*)
+    KEEP (*(.gnu.linkonce.d.*personality*))
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  _edata = .; PROVIDE (edata = .);
+  __bss_start = .;
+  __bss_start__ = .;
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.
+      FIXME: Why do we need it? When there is no .bss section, we don't
+      pad the .data section.  */
+   . = ALIGN(. != 0 ? 32 / 8 : 1);
+  }
+  _bss_end__ = . ; __bss_end__ = . ;
+  . = ALIGN(32 / 8);
+  . = ALIGN(32 / 8);
+  __end__ = . ;
+  _end = .; PROVIDE (end = .);
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* Adding the word ABSOLUTE below, so that the _stack below won't float
+     into a random section. If _stack is not absolutely with .stack section,
+     we saw that sometimes _stack got inserted into the .debug_frame section
+     because it's processed by the linker at that moment. As a result, _stack
+     symbol will get wrongly moved and gelf_update_symshndx() will return
+     invalid data. */
+    .stack         0x80000 :
+  {
+    _stack = ABSOLUTE(.);
+    *(.stack)
+  }
+  .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
+  .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) }
+  /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/build/core/armelflib.x b/build/core/armelflib.x
new file mode 100644 (file)
index 0000000..0150e02
--- /dev/null
@@ -0,0 +1,164 @@
+/* Default linker script, for normal executables */
+OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
+             "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SEARCH_DIR("/usr/local/armdev/arm-elf/lib");
+/* Do we need any of these for elf?
+   __DYNAMIC = 0;    */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+/*  PROVIDE (__executable_start = 0x8000); . = 0x8000; */
+. = 0 + SIZEOF_HEADERS; 
+  .interp         : { *(.interp) }
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0
+  .plt            : { *(.plt) }
+  .text           :
+  {
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    KEEP (*(.text.*personality*))
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.glue_7t) *(.glue_7)
+  } =0
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
+   __exidx_start = .;
+  .ARM.exidx   : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }
+   __exidx_end = .;
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : ONLY_IF_RO { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN(256) + (. & (256 - 1));
+  /* Exception handling  */
+  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : ONLY_IF_RW { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) }
+  /* Thread Local Storage sections  */
+  .tdata         : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss                  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  /* Ensure the __preinit_array_start label is properly aligned.  We
+     could instead move the label definition inside the section, but
+     the linker would then create the section even if it turns out to
+     be empty, which isn't pretty.  */
+  . = ALIGN(32 / 8);
+  PROVIDE (__preinit_array_start = .);
+  .preinit_array     : { KEEP (*(.preinit_array)) }
+  PROVIDE (__preinit_array_end = .);
+  PROVIDE (__init_array_start = .);
+  .init_array     : { KEEP (*(.init_array)) }
+  PROVIDE (__init_array_end = .);
+  PROVIDE (__fini_array_start = .);
+  .fini_array     : { KEEP (*(.fini_array)) }
+  PROVIDE (__fini_array_end = .);
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin*.o(.ctors))
+    /* We don't want to include the .ctor section from
+       from the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin*.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) }
+  .got            : { *(.got.plt) *(.got) }
+  .data           :
+  {
+    __data_start = . ;
+    *(.data .data.* .gnu.linkonce.d.*)
+    KEEP (*(.gnu.linkonce.d.*personality*))
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  _edata = .;
+  PROVIDE (edata = .);
+  .dynamic        : { *(.dynamic) }
+  .hash           : { *(.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+/*  .shstrtab    : { *(.shstrtab) } */
+  .rel.plt        : { *(.rel.plt) }
+  .rel.dyn       : { *(.rel.*) }
+  __bss_start = .;
+  __bss_start__ = .;
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.  */
+   . = ALIGN(32 / 8);
+  }
+  . = ALIGN(32 / 8);
+  _end = .;
+  _bss_end__ = . ; __bss_end__ = . ; __end__ = . ;
+  PROVIDE (end = .);
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
+  /DISCARD/ : { *(.note.GNU-stack) *(.comment*) *(.stack*) *(.shstrtab) }
+}
diff --git a/build/core/base_rules.mk b/build/core/base_rules.mk
new file mode 100644 (file)
index 0000000..a7456e8
--- /dev/null
@@ -0,0 +1,608 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Users can define base-rules-hook in their buildspec.mk to perform
+# arbitrary operations as each module is included.
+ifdef base-rules-hook
+$(if $(base-rules-hook),)
+endif
+
+###########################################################
+## Common instructions for a generic module.
+###########################################################
+
+LOCAL_MODULE := $(strip $(LOCAL_MODULE))
+ifeq ($(LOCAL_MODULE),)
+  $(error $(LOCAL_PATH): LOCAL_MODULE is not defined)
+endif
+
+LOCAL_IS_HOST_MODULE := $(strip $(LOCAL_IS_HOST_MODULE))
+ifdef LOCAL_IS_HOST_MODULE
+  ifneq ($(LOCAL_IS_HOST_MODULE),true)
+    $(error $(LOCAL_PATH): LOCAL_IS_HOST_MODULE must be "true" or empty, not "$(LOCAL_IS_HOST_MODULE)")
+  endif
+  my_prefix:=HOST_
+  my_host:=host-
+else
+  my_prefix:=TARGET_
+  my_host:=
+endif
+
+###########################################################
+## Validate and define fallbacks for input LOCAL_* variables.
+###########################################################
+
+## Dump a .csv file of all modules and their tags
+#ifneq ($(tag-list-first-time),false)
+#$(shell rm -f tag-list.csv)
+#tag-list-first-time := false
+#endif
+#comma := ,
+#empty :=
+#space := $(empty) $(empty)
+#$(shell echo $(lastword $(filter-out config/% out/%,$(MAKEFILE_LIST))),$(LOCAL_MODULE),$(strip $(LOCAL_MODULE_CLASS)),$(subst $(space),$(comma),$(sort $(LOCAL_MODULE_TAGS))) >> tag-list.csv)
+
+LOCAL_MODULE_TAGS := $(sort $(LOCAL_MODULE_TAGS))
+ifeq (,$(LOCAL_MODULE_TAGS))
+# Modules without tags fall back to user (which is changed to user eng below)
+LOCAL_MODULE_TAGS := user
+#$(warning default tags: $(lastword $(filter-out config/% out/%,$(MAKEFILE_LIST))))
+endif
+
+# Only the tags mentioned in this test are expected to be set by module
+# makefiles. Anything else is either a typo or a source of unexpected
+# behaviors.
+ifneq ($(filter-out user debug eng tests optional samples shell_ash shell_mksh,$(LOCAL_MODULE_TAGS)),)
+$(warning unusual tags $(LOCAL_MODULE_TAGS) on $(LOCAL_MODULE) at $(LOCAL_PATH))
+endif
+
+ifneq ($(filter $(LOCAL_MODULE_TAGS),user),)
+  ifeq ($(filter $(GRANDFATHERED_USER_MODULES),$(LOCAL_MODULE)),)
+    $(warning *** Module name: $(LOCAL_MODULE))
+    $(warning *** Makefile location: $(LOCAL_PATH))
+    $(warning * )
+    $(warning * Each module must use a LOCAL_MODULE_TAGS in its)
+    $(warning * Android.mk. Possible tags declared by a module:)
+    $(warning * )
+    $(warning *     optional, debug, eng, tests, samples)
+    $(warning * )
+    $(warning * If the module is expected to be in all builds)
+    $(warning * of a product, then it should use the)
+    $(warning * "optional" tag: )
+    $(warning * )
+    $(warning *    Add "LOCAL_MODULE_TAGS := optional" in the)
+    $(warning *    Android.mk for the affected module, and add)
+    $(warning *    the LOCAL_MODULE value for that component)
+    $(warning *    into the PRODUCT_PACKAGES section of product)
+    $(warning *    makefile(s) where it's necessary, if)
+    $(warning *    appropriate.)
+    $(warning * )
+    $(warning * If the component should be in EVERY build of ALL)
+    $(warning * products, then add its LOCAL_MODULE value to the)
+    $(warning * PRODUCT_PACKAGES section of)
+    $(warning * build/target/product/core.mk)
+    $(warning * )
+    $(error user tag detected on new module - user tags are only supported on legacy modules)
+  endif
+endif
+
+# Add implicit tags.
+#
+# If the local directory or one of its parents contains a MODULE_LICENSE_GPL
+# file, tag the module as "gnu".  Search for "*_GNU*" so that we can also
+# find files like MODULE_LICENSE_GPL_AND_AFL but exclude files like
+# MODULE_LICENSE_LGPL.
+#
+ifneq ($(call find-parent-file,$(LOCAL_PATH),MODULE_LICENSE*_GPL*),)
+  LOCAL_MODULE_TAGS += gnu
+endif
+
+#
+# If this module is listed on CUSTOM_MODULES, promote it to "user"
+# so that it will be installed in $(TARGET_OUT).
+#
+ifneq (,$(filter $(LOCAL_MODULE),$(CUSTOM_MODULES)))
+  LOCAL_MODULE_TAGS := $(sort $(LOCAL_MODULE_TAGS) user)
+endif
+
+# The definition of should-install-to-system will be different depending
+# on which goal (e.g., sdk or just droid) is being built.
+ifdef LOCAL_IS_HOST_MODULE
+  use_data :=
+else
+  use_data := $(if $(call should-install-to-system,$(LOCAL_MODULE_TAGS)),,_DATA)
+endif
+
+LOCAL_MODULE_CLASS := $(strip $(LOCAL_MODULE_CLASS))
+ifneq ($(words $(LOCAL_MODULE_CLASS)),1)
+  $(error $(LOCAL_PATH): LOCAL_MODULE_CLASS must contain exactly one word, not "$(LOCAL_MODULE_CLASS)")
+endif
+
+# Those used to be implicitly ignored, but aren't any more.
+# As of 20100110 there are no apps with the user tag.
+ifeq ($(LOCAL_MODULE_CLASS),APPS)
+  ifneq ($(filter $(LOCAL_MODULE_TAGS),user),)
+    $(warning user tag on app $(LOCAL_MODULE) at $(LOCAL_PATH) - add your app to core.mk instead)
+  endif
+endif
+
+LOCAL_MODULE_PATH := $(strip $(LOCAL_MODULE_PATH))
+ifeq ($(LOCAL_MODULE_PATH),)
+  LOCAL_MODULE_PATH := $($(my_prefix)OUT$(use_data)_$(LOCAL_MODULE_CLASS))
+  ifeq ($(strip $(LOCAL_MODULE_PATH)),)
+    $(error $(LOCAL_PATH): unhandled LOCAL_MODULE_CLASS "$(LOCAL_MODULE_CLASS)")
+  endif
+endif
+
+ifneq ($(strip $(LOCAL_BUILT_MODULE)$(LOCAL_INSTALLED_MODULE)),)
+  $(error $(LOCAL_PATH): LOCAL_BUILT_MODULE and LOCAL_INSTALLED_MODULE must not be defined by component makefiles)
+endif
+
+# Make sure that this IS_HOST/CLASS/MODULE combination is unique.
+module_id := MODULE.$(if \
+    $(LOCAL_IS_HOST_MODULE),HOST,TARGET).$(LOCAL_MODULE_CLASS).$(LOCAL_MODULE)
+ifdef $(module_id)
+$(error $(LOCAL_PATH): $(module_id) already defined by $($(module_id)))
+endif
+$(module_id) := $(LOCAL_PATH)
+
+intermediates := $(call local-intermediates-dir)
+intermediates.COMMON := $(call local-intermediates-dir,COMMON)
+
+###########################################################
+# Pick a name for the intermediate and final targets
+###########################################################
+LOCAL_MODULE_STEM := $(strip $(LOCAL_MODULE_STEM))
+ifeq ($(LOCAL_MODULE_STEM),)
+  LOCAL_MODULE_STEM := $(LOCAL_MODULE)
+endif
+LOCAL_INSTALLED_MODULE_STEM := $(LOCAL_MODULE_STEM)$(LOCAL_MODULE_SUFFIX)
+
+LOCAL_BUILT_MODULE_STEM := $(strip $(LOCAL_BUILT_MODULE_STEM))
+ifeq ($(LOCAL_BUILT_MODULE_STEM),)
+  LOCAL_BUILT_MODULE_STEM := $(LOCAL_INSTALLED_MODULE_STEM)
+endif
+
+# OVERRIDE_BUILT_MODULE_PATH is only allowed to be used by the
+# internal SHARED_LIBRARIES build files.
+OVERRIDE_BUILT_MODULE_PATH := $(strip $(OVERRIDE_BUILT_MODULE_PATH))
+ifdef OVERRIDE_BUILT_MODULE_PATH
+  ifneq ($(LOCAL_MODULE_CLASS),SHARED_LIBRARIES)
+    $(error $(LOCAL_PATH): Illegal use of OVERRIDE_BUILT_MODULE_PATH)
+  endif
+  built_module_path := $(OVERRIDE_BUILT_MODULE_PATH)
+else
+  built_module_path := $(intermediates)
+endif
+LOCAL_BUILT_MODULE := $(built_module_path)/$(LOCAL_BUILT_MODULE_STEM)
+built_module_path :=
+
+# LOCAL_UNINSTALLABLE_MODULE is only allowed to be used by the
+# internal STATIC_LIBRARIES build files.
+LOCAL_UNINSTALLABLE_MODULE := $(strip $(LOCAL_UNINSTALLABLE_MODULE))
+ifdef LOCAL_UNINSTALLABLE_MODULE
+  ifeq (,$(filter $(LOCAL_MODULE_CLASS),JAVA_LIBRARIES STATIC_LIBRARIES))
+    $(error $(LOCAL_PATH): Illegal use of LOCAL_UNINSTALLABLE_MODULE)
+  endif
+else
+  LOCAL_INSTALLED_MODULE := $(LOCAL_MODULE_PATH)/$(LOCAL_MODULE_SUBDIR)$(LOCAL_INSTALLED_MODULE_STEM)
+endif
+
+# Assemble the list of targets to create PRIVATE_ variables for.
+LOCAL_INTERMEDIATE_TARGETS += $(LOCAL_BUILT_MODULE)
+
+
+###########################################################
+## AIDL: Compile .aidl files to .java
+###########################################################
+
+aidl_sources := $(filter %.aidl,$(LOCAL_SRC_FILES))
+
+ifneq ($(strip $(aidl_sources)),)
+
+aidl_java_sources := $(patsubst %.aidl,%.java,$(addprefix $(intermediates.COMMON)/src/, $(aidl_sources)))
+aidl_sources := $(addprefix $(TOP_DIR)$(LOCAL_PATH)/, $(aidl_sources))
+
+aidl_preprocess_import :=
+LOCAL_SDK_VERSION:=$(strip $(LOCAL_SDK_VERSION))
+ifdef LOCAL_SDK_VERSION
+ifeq ($(LOCAL_SDK_VERSION),current)
+  aidl_preprocess_import := $(TARGET_OUT_COMMON_INTERMEDIATES)/framework.aidl
+else
+  aidl_preprocess_import := $(HISTORICAL_SDK_VERSIONS_ROOT)/$(LOCAL_SDK_VERSION)/framework.aidl
+endif # !current
+endif # LOCAL_SDK_VERSION
+$(aidl_java_sources): PRIVATE_AIDL_FLAGS := -b $(addprefix -p,$(aidl_preprocess_import)) -I$(LOCAL_PATH) -I$(LOCAL_PATH)/src $(addprefix -I,$(LOCAL_AIDL_INCLUDES))
+
+$(aidl_java_sources): $(intermediates.COMMON)/src/%.java: $(TOPDIR)$(LOCAL_PATH)/%.aidl $(PRIVATE_ADDITIONAL_DEPENDENCIES) $(AIDL) $(aidl_preprocess_import)
+       $(transform-aidl-to-java)
+-include $(aidl_java_sources:%.java=%.P)
+
+else
+aidl_java_sources :=
+endif
+
+###########################################################
+## logtags: Add .logtags files to global list, emit java source
+###########################################################
+
+logtags_sources := $(filter %.logtags,$(LOCAL_SRC_FILES))
+
+ifneq ($(strip $(logtags_sources)),)
+
+event_log_tags := $(addprefix $(LOCAL_PATH)/,$(logtags_sources))
+
+# Emit a java source file with constants for the tags, if
+# LOCAL_MODULE_CLASS is "APPS" or "JAVA_LIBRARIES".
+ifneq ($(strip $(filter $(LOCAL_MODULE_CLASS),APPS JAVA_LIBRARIES)),)
+
+logtags_java_sources := $(patsubst %.logtags,%.java,$(addprefix $(intermediates.COMMON)/src/, $(logtags_sources)))
+logtags_sources := $(addprefix $(TOP_DIR)$(LOCAL_PATH)/, $(logtags_sources))
+
+$(logtags_java_sources): $(intermediates.COMMON)/src/%.java: $(TOPDIR)$(LOCAL_PATH)/%.logtags $(TARGET_OUT_COMMON_INTERMEDIATES)/all-event-log-tags.txt
+       $(transform-logtags-to-java)
+
+endif
+
+else
+logtags_java_sources :=
+event_log_tags :=
+endif
+
+###########################################################
+## .proto files: Compile proto files to .java
+###########################################################
+proto_sources := $(filter %.proto,$(LOCAL_SRC_FILES))
+# Because names of the .java files compiled from .proto files are unknown until the
+# .proto files are compiled, we use a timestamp file as depedency.
+proto_java_sources_file_stamp :=
+ifneq ($(proto_sources),)
+proto_sources_fullpath := $(addprefix $(TOP_DIR)$(LOCAL_PATH)/, $(proto_sources))
+# By putting the generated java files into $(LOCAL_INTERMEDIATE_SOURCE_DIR), they will be
+# automatically found by the java compiling function transform-java-to-classes.jar.
+ifneq ($(LOCAL_INTERMEDIATE_SOURCE_DIR),)
+proto_java_intemediate_dir := $(LOCAL_INTERMEDIATE_SOURCE_DIR)/proto
+else
+# LOCAL_INTERMEDIATE_SOURCE_DIR may be not defined in non-java modules.
+proto_java_intemediate_dir := $(intermediates)/proto
+endif
+proto_java_sources_file_stamp := $(proto_java_intemediate_dir)/Proto.stamp
+proto_java_sources_dir := $(proto_java_intemediate_dir)/src
+
+$(proto_java_sources_file_stamp): PRIVATE_PROTO_INCLUDES := $(TOP)
+$(proto_java_sources_file_stamp): PRIVATE_PROTO_SRC_FILES := $(proto_sources_fullpath)
+$(proto_java_sources_file_stamp): PRIVATE_PROTO_JAVA_OUTPUT_DIR := $(proto_java_sources_dir)
+ifeq ($(LOCAL_PROTOC_OPTIMIZE_TYPE),micro)
+$(proto_java_sources_file_stamp): PRIVATE_PROTO_JAVA_OUTPUT_OPTION := --javamicro_out
+else
+$(proto_java_sources_file_stamp): PRIVATE_PROTO_JAVA_OUTPUT_OPTION := --java_out
+endif
+$(proto_java_sources_file_stamp): PRIVATE_PROTOC_FLAGS := $(LOCAL_PROTOC_FLAGS)
+$(proto_java_sources_file_stamp) : $(proto_sources_fullpath) $(PROTOC)
+       $(call transform-proto-to-java)
+
+#TODO: protoc should output the dependencies introduced by imports.
+
+LOCAL_INTERMEDIATE_TARGETS += $(proto_java_sources_file_stamp)
+endif # proto_sources
+
+
+###########################################################
+## Java: Compile .java files to .class
+###########################################################
+#TODO: pull this into java.make once host and target are combined
+
+java_sources := $(addprefix $(TOP_DIR)$(LOCAL_PATH)/, $(filter %.java,$(LOCAL_SRC_FILES))) $(aidl_java_sources) $(logtags_java_sources) \
+                $(filter %.java,$(LOCAL_GENERATED_SOURCES))
+all_java_sources := $(java_sources) $(addprefix $($(my_prefix)OUT_COMMON_INTERMEDIATES)/, $(filter %.java,$(LOCAL_INTERMEDIATE_SOURCES)))
+
+## Java resources #########################################
+
+# Look for resource files in any specified directories.
+# Non-java and non-doc files will be picked up as resources
+# and included in the output jar file.
+java_resource_file_groups :=
+
+LOCAL_JAVA_RESOURCE_DIRS := $(strip $(LOCAL_JAVA_RESOURCE_DIRS))
+ifneq ($(LOCAL_JAVA_RESOURCE_DIRS),)
+  # This makes a list of words like
+  #     <dir1>::<file1>:<file2> <dir2>::<file1> <dir3>:
+  # where each of the files is relative to the directory it's grouped with.
+  # Directories that don't contain any resource files will result in groups
+  # that end with a colon, and they are stripped out in the next step.
+  java_resource_file_groups += \
+    $(foreach dir,$(LOCAL_JAVA_RESOURCE_DIRS), \
+       $(subst $(space),:,$(strip \
+               $(TOP_DIR)$(LOCAL_PATH)/$(dir): \
+           $(patsubst ./%,%,$(shell cd $(TOP_DIR)$(LOCAL_PATH)/$(dir) && \
+               find . \
+                   -type d -a -name ".svn" -prune -o \
+                   -type f \
+                       -a \! -name "*.java" \
+                       -a \! -name "package.html" \
+                       -a \! -name "overview.html" \
+                       -a \! -name ".*.swp" \
+                       -a \! -name ".DS_Store" \
+                       -a \! -name "*~" \
+                       -print \
+                   )) \
+       )) \
+    )
+  java_resource_file_groups := $(filter-out %:,$(java_resource_file_groups))
+endif # LOCAL_JAVA_RESOURCE_DIRS
+
+LOCAL_JAVA_RESOURCE_FILES := $(strip $(LOCAL_JAVA_RESOURCE_FILES))
+ifneq ($(LOCAL_JAVA_RESOURCE_FILES),)
+  java_resource_file_groups += \
+    $(foreach f,$(LOCAL_JAVA_RESOURCE_FILES), \
+       $(patsubst %/,%,$(dir $(f)))::$(notdir $(f)) \
+     )
+endif # LOCAL_JAVA_RESOURCE_FILES
+
+ifdef java_resource_file_groups
+  # The full paths to all resources, used for dependencies.
+  java_resource_sources := \
+    $(foreach group,$(java_resource_file_groups), \
+       $(addprefix $(word 1,$(subst :,$(space),$(group)))/, \
+           $(wordlist 2,9999,$(subst :,$(space),$(group))) \
+       ) \
+    )
+  # The arguments to jar that will include these files in a jar file.
+  extra_jar_args := \
+    $(foreach group,$(java_resource_file_groups), \
+       $(addprefix -C $(word 1,$(subst :,$(space),$(group))) , \
+           $(wordlist 2,9999,$(subst :,$(space),$(group))) \
+       ) \
+    )
+  java_resource_file_groups :=
+else
+  java_resource_sources :=
+  extra_jar_args :=
+endif # java_resource_file_groups
+
+## PRIVATE java vars ######################################
+
+ifneq ($(strip $(all_java_sources)$(all_res_assets)),)
+
+full_static_java_libs := \
+    $(foreach lib,$(LOCAL_STATIC_JAVA_LIBRARIES), \
+      $(call intermediates-dir-for, \
+        JAVA_LIBRARIES,$(lib),$(LOCAL_IS_HOST_MODULE),COMMON)/javalib.jar)
+
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_INSTALL_DIR := $(dir $(LOCAL_INSTALLED_MODULE))
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_CLASS_INTERMEDIATES_DIR := $(intermediates)/classes
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_SOURCE_INTERMEDIATES_DIR := $(intermediates)/src
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_JAVA_SOURCES := $(all_java_sources)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_JAVA_OBJECTS := $(patsubst %.java,%.class,$(LOCAL_SRC_FILES))
+ifeq ($(my_prefix),TARGET_)
+ifeq ($(LOCAL_SDK_VERSION),)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_BOOTCLASSPATH := -bootclasspath $(call java-lib-files,core)
+else
+ifeq ($(LOCAL_SDK_VERSION),current)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_BOOTCLASSPATH := -bootclasspath $(call java-lib-files,android_stubs_current)
+else
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_BOOTCLASSPATH := -bootclasspath $(call java-lib-files,sdk_v$(LOCAL_SDK_VERSION))
+endif # current
+endif # LOCAL_SDK_VERSION
+endif # TARGET_
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_RESOURCE_DIR := $(LOCAL_RESOURCE_DIR)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_EXTRA_JAR_ARGS := $(extra_jar_args)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_ASSET_DIR := $(LOCAL_ASSET_DIR)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_STATIC_JAVA_LIBRARIES := $(full_static_java_libs)
+
+# full_java_libs: The list of files that should be used as the classpath.
+#                 Using this list as a dependency list WILL NOT WORK.
+# full_java_lib_deps: Should be specified as a prerequisite of this module
+#                 to guarantee that the files in full_java_libs will
+#                 be up-to-date.
+ifdef LOCAL_IS_HOST_MODULE
+# TODO: make prebuilt java libraries use the same
+#       intermediates path pattern as target java libraries.
+ifeq ($(LOCAL_BUILD_HOST_DEX),true)
+full_java_libs := $(call java-lib-files,$(LOCAL_JAVA_LIBRARIES),$(LOCAL_IS_HOST_MODULE))
+full_java_lib_deps := $(call java-lib-deps,$(LOCAL_JAVA_LIBRARIES),$(LOCAL_IS_HOST_MODULE))
+else
+full_java_libs := $(addprefix $(HOST_OUT_JAVA_LIBRARIES)/,$(addsuffix $(COMMON_JAVA_PACKAGE_SUFFIX),$(LOCAL_JAVA_LIBRARIES)))
+full_java_lib_deps := $(full_java_libs)
+endif # LOCAL_BUILD_HOST_DEX
+else
+full_java_libs := $(call java-lib-files,$(LOCAL_JAVA_LIBRARIES),$(LOCAL_IS_HOST_MODULE))
+full_java_lib_deps := $(call java-lib-deps,$(LOCAL_JAVA_LIBRARIES),$(LOCAL_IS_HOST_MODULE))
+endif # !LOCAL_IS_HOST_MODULE
+full_java_libs += $(full_static_java_libs) $(LOCAL_CLASSPATH)
+full_java_lib_deps += $(full_static_java_libs) $(LOCAL_CLASSPATH)
+
+# This is set by packages that contain instrumentation, allowing them to
+# link against the package they are instrumenting.  Currently only one such
+# package is allowed.
+LOCAL_INSTRUMENTATION_FOR := $(strip $(LOCAL_INSTRUMENTATION_FOR))
+ifdef LOCAL_INSTRUMENTATION_FOR
+  ifneq ($(words $(LOCAL_INSTRUMENTATION_FOR)),1)
+    $(error \
+        $(LOCAL_PATH): Multiple LOCAL_INSTRUMENTATION_FOR members defined)
+  endif
+
+  link_instr_intermediates_dir := $(call intermediates-dir-for, \
+      APPS,$(LOCAL_INSTRUMENTATION_FOR))
+  link_instr_intermediates_dir.COMMON := $(call intermediates-dir-for, \
+      APPS,$(LOCAL_INSTRUMENTATION_FOR),,COMMON)
+
+  # link against the jar with full original names (before proguard processing).
+  full_java_libs += $(link_instr_intermediates_dir.COMMON)/classes.jar
+  full_java_lib_deps += $(link_instr_intermediates_dir.COMMON)/classes.jar
+endif
+
+ifneq ($(strip $(LOCAL_JAR_MANIFEST)),)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_JAR_MANIFEST := $(LOCAL_PATH)/$(LOCAL_JAR_MANIFEST)
+else
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_JAR_MANIFEST :=
+endif
+
+endif
+
+
+###########################################################
+## make clean- targets
+###########################################################
+cleantarget := clean-$(LOCAL_MODULE)
+$(cleantarget) : PRIVATE_MODULE := $(LOCAL_MODULE)
+$(cleantarget) : PRIVATE_CLEAN_FILES := \
+               $(PRIVATE_CLEAN_FILES) \
+               $(LOCAL_BUILT_MODULE) \
+               $(LOCAL_INSTALLED_MODULE) \
+               $(intermediates)
+$(cleantarget)::
+       @echo "Clean: $(PRIVATE_MODULE)"
+       $(hide) rm -rf $(PRIVATE_CLEAN_FILES)
+
+###########################################################
+## Common definitions for module.
+###########################################################
+
+# Propagate local configuration options to this target.
+$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_PATH:=$(LOCAL_PATH)
+$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_POST_PROCESS_COMMAND:= $(LOCAL_POST_PROCESS_COMMAND)
+$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_AAPT_FLAGS:= $(LOCAL_AAPT_FLAGS)
+$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_JAVA_LIBRARIES:= $(LOCAL_JAVA_LIBRARIES)
+$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_MANIFEST_PACKAGE_NAME:= $(LOCAL_MANIFEST_PACKAGE_NAME)
+$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_MANIFEST_INSTRUMENTATION_FOR:= $(LOCAL_MANIFEST_INSTRUMENTATION_FOR)
+
+$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_ALL_JAVA_LIBRARIES:= $(full_java_libs)
+$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_IS_HOST_MODULE := $(LOCAL_IS_HOST_MODULE)
+$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_HOST:= $(my_host)
+
+$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_INTERMEDIATES_DIR:= $(intermediates)
+
+# Tell the module and all of its sub-modules who it is.
+$(LOCAL_INTERMEDIATE_TARGETS) : PRIVATE_MODULE:= $(LOCAL_MODULE)
+
+# Provide a short-hand for building this module.
+# We name both BUILT and INSTALLED in case
+# LOCAL_UNINSTALLABLE_MODULE is set.
+.PHONY: $(LOCAL_MODULE)
+$(LOCAL_MODULE): $(LOCAL_BUILT_MODULE) $(LOCAL_INSTALLED_MODULE)
+
+###########################################################
+## Module installation rule
+###########################################################
+
+# Some hosts do not have ACP; override the LOCAL version if that's the case.
+ifneq ($(strip $(HOST_ACP_UNAVAILABLE)),)
+  LOCAL_ACP_UNAVAILABLE := $(strip $(HOST_ACP_UNAVAILABLE))
+endif
+
+ifndef LOCAL_UNINSTALLABLE_MODULE
+  # Define a copy rule to install the module.
+  # acp and libraries that it uses can't use acp for
+  # installation;  hence, LOCAL_ACP_UNAVAILABLE.
+ifneq ($(LOCAL_ACP_UNAVAILABLE),true)
+$(LOCAL_INSTALLED_MODULE): $(LOCAL_BUILT_MODULE) | $(ACP)
+       @echo "Install: $@"
+       $(copy-file-to-target)
+else
+$(LOCAL_INSTALLED_MODULE): $(LOCAL_BUILT_MODULE)
+       @echo "Install: $@"
+       $(copy-file-to-target-with-cp)
+endif
+
+ifeq ($(LOCAL_DEX_PREOPT),true)
+installed_odex := $(basename $(LOCAL_INSTALLED_MODULE)).odex
+built_odex := $(basename $(LOCAL_BUILT_MODULE)).odex
+$(installed_odex) : $(built_odex) | $(ACP)
+       @echo "Install: $@"
+       $(copy-file-to-target)
+
+$(LOCAL_INSTALLED_MODULE) : | $(installed_odex)
+endif
+
+endif # !LOCAL_UNINSTALLABLE_MODULE
+
+
+###########################################################
+## CHECK_BUILD goals
+###########################################################
+
+# If nobody has defined a more specific module for the
+# checked modules, use LOCAL_BUILT_MODULE.  This was old
+# behavior, so it should be a safe default.
+ifndef LOCAL_CHECKED_MODULE
+  ifndef LOCAL_SDK_VERSION
+    LOCAL_CHECKED_MODULE := $(LOCAL_BUILT_MODULE)
+  endif
+endif
+
+# If they request that this module not be checked, then don't.
+# PLEASE DON'T SET THIS.  ANY PLACES THAT SET THIS WITHOUT
+# GOOD REASON WILL HAVE IT REMOVED.
+ifdef LOCAL_DONT_CHECK_MODULE
+  LOCAL_CHECKED_MODULE :=
+endif
+
+###########################################################
+## Register with ALL_MODULES
+###########################################################
+
+ALL_MODULES += $(LOCAL_MODULE)
+
+# Don't use += on subvars, or else they'll end up being
+# recursively expanded.
+ALL_MODULES.$(LOCAL_MODULE).CLASS := \
+    $(ALL_MODULES.$(LOCAL_MODULE).CLASS) $(LOCAL_MODULE_CLASS)
+ALL_MODULES.$(LOCAL_MODULE).PATH := \
+    $(ALL_MODULES.$(LOCAL_MODULE).PATH) $(LOCAL_PATH)
+ALL_MODULES.$(LOCAL_MODULE).TAGS := \
+    $(ALL_MODULES.$(LOCAL_MODULE).TAGS) $(LOCAL_MODULE_TAGS)
+ALL_MODULES.$(LOCAL_MODULE).CHECKED := \
+    $(ALL_MODULES.$(LOCAL_MODULE).CHECKED) $(LOCAL_CHECKED_MODULE)
+ALL_MODULES.$(LOCAL_MODULE).BUILT := \
+    $(ALL_MODULES.$(LOCAL_MODULE).BUILT) $(LOCAL_BUILT_MODULE)
+ALL_MODULES.$(LOCAL_MODULE).INSTALLED := \
+    $(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(LOCAL_INSTALLED_MODULE)
+ALL_MODULES.$(LOCAL_MODULE).REQUIRED := \
+    $(ALL_MODULES.$(LOCAL_MODULE).REQUIRED) $(LOCAL_REQUIRED_MODULES)
+ALL_MODULES.$(LOCAL_MODULE).EVENT_LOG_TAGS := \
+    $(ALL_MODULES.$(LOCAL_MODULE).EVENT_LOG_TAGS) $(event_log_tags)
+ALL_MODULES.$(LOCAL_MODULE).INTERMEDIATE_SOURCE_DIR := \
+    $(ALL_MODULES.$(LOCAL_MODULE).INTERMEDIATE_SOURCE_DIR) $(LOCAL_INTERMEDIATE_SOURCE_DIR)
+
+INSTALLABLE_FILES.$(LOCAL_INSTALLED_MODULE).MODULE := $(LOCAL_MODULE)
+
+###########################################################
+## Take care of LOCAL_MODULE_TAGS
+###########################################################
+
+# Keep track of all the tags we've seen.
+ALL_MODULE_TAGS := $(sort $(ALL_MODULE_TAGS) $(LOCAL_MODULE_TAGS))
+
+# Add this module to the tag list of each specified tag.
+# Don't use "+=". If the variable hasn't been set with ":=",
+# it will default to recursive expansion.
+$(foreach tag,$(LOCAL_MODULE_TAGS),\
+    $(eval ALL_MODULE_TAGS.$(tag) := \
+           $(ALL_MODULE_TAGS.$(tag)) \
+           $(LOCAL_INSTALLED_MODULE)))
+
+# Add this module name to the tag list of each specified tag.
+$(foreach tag,$(LOCAL_MODULE_TAGS),\
+    $(eval ALL_MODULE_NAME_TAGS.$(tag) += $(LOCAL_MODULE)))
+
+###########################################################
+## NOTICE files
+###########################################################
+
+include $(BUILD_SYSTEM)/notice_files.mk
+
+#:vi noexpandtab
diff --git a/build/core/binary.mk b/build/core/binary.mk
new file mode 100644 (file)
index 0000000..88c356a
--- /dev/null
@@ -0,0 +1,568 @@
+###########################################################
+## Standard rules for building binary object files from
+## asm/c/cpp/yacc/lex source files.
+##
+## The list of object files is exported in $(all_objects).
+###########################################################
+
+######################################
+## Sanity check for LOCAL_NDK_VERSION
+######################################
+my_ndk_version_root :=
+ifeq ($(TARGET_SIMULATOR),true)
+  # NDK does not support sim build.
+  LOCAL_NDK_VERSION :=
+endif
+ifdef LOCAL_NDK_VERSION
+  ifdef LOCAL_IS_HOST_MODULE
+    $(error $(LOCAL_PATH): LOCAL_NDK_VERSION can not be used in host module)
+  endif
+  ifneq ($(filter-out SHARED_LIBRARIES STATIC_LIBRARIES,$(LOCAL_MODULE_CLASS)),)
+    $(error $(LOCAL_PATH): LOCAL_NDK_VERSION can only be used to build target shared/static libraries, \
+          while your module is of class $(LOCAL_MODULE_CLASS))
+  endif
+  ifeq ($(filter $(LOCAL_NDK_VERSION),$(TARGET_AVAILABLE_NDK_VERSIONS)),)
+    $(error $(LOCAL_PATH): Invalid LOCAL_NDK_VERSION '$(LOCAL_NDK_VERSION)' \
+           Choices are $(TARGET_AVAILABLE_NDK_VERSIONS))
+  endif
+  ifndef LOCAL_SDK_VERSION
+    $(error $(LOCAL_PATH): LOCAL_NDK_VERSION must be defined with LOCAL_SDK_VERSION)
+  endif
+  my_ndk_version_root := $(HISTORICAL_NDK_VERSIONS_ROOT)/android-ndk-r$(LOCAL_NDK_VERSION)/platforms/android-$(LOCAL_SDK_VERSION)/arch-$(TARGET_ARCH)
+  ifeq ($(wildcard $(my_ndk_version_root)),)
+    $(error $(LOCAL_PATH): ndk version root does not exist: $(my_ndk_version_root))
+  endif
+endif
+
+#######################################
+include $(BUILD_SYSTEM)/base_rules.mk
+#######################################
+
+####################################################
+## Add FDO flags if FDO is turned on and supported
+####################################################
+ifeq ($(strip $(LOCAL_NO_FDO_SUPPORT)),)
+  LOCAL_CFLAGS += $(TARGET_FDO_CFLAGS)
+  LOCAL_CPPFLAGS += $(TARGET_FDO_CFLAGS)
+  LOCAL_LDFLAGS += $(TARGET_FDO_CFLAGS)
+endif
+
+###########################################################
+## Explicitly declare assembly-only __ASSEMBLY__ macro for
+## assembly source
+###########################################################
+LOCAL_ASFLAGS += -D__ASSEMBLY__
+
+###########################################################
+## Define PRIVATE_ variables from global vars
+###########################################################
+ifdef LOCAL_NDK_VERSION
+my_target_project_includes :=
+my_target_c_inclues := $(my_ndk_version_root)/usr/include
+# TODO: more reliable way to remove platform stuff.
+my_target_global_cflags := $(filter-out -include -I system/%, $(TARGET_GLOBAL_CFLAGS))
+my_target_global_cppflags := $(filter-out -include -I system/%, $(TARGET_GLOBAL_CPPFLAGS))
+else
+my_target_project_includes := $(TARGET_PROJECT_INCLUDES)
+my_target_c_inclues := $(TARGET_C_INCLUDES)
+my_target_global_cflags := $(TARGET_GLOBAL_CFLAGS)
+my_target_global_cppflags := $(TARGET_GLOBAL_CPPFLAGS)
+endif
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_TARGET_PROJECT_INCLUDES := $(my_target_project_includes)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_TARGET_C_INCLUDES := $(my_target_c_inclues)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_TARGET_GLOBAL_CFLAGS := $(my_target_global_cflags)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_TARGET_GLOBAL_CPPFLAGS := $(my_target_global_cppflags)
+
+###########################################################
+## Define PRIVATE_ variables used by multiple module types
+###########################################################
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_NO_DEFAULT_COMPILER_FLAGS := \
+       $(strip $(LOCAL_NO_DEFAULT_COMPILER_FLAGS))
+
+ifeq ($(strip $(LOCAL_CC)),)
+  LOCAL_CC := $($(my_prefix)CC)
+endif
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_CC := $(LOCAL_CC)
+
+ifeq ($(strip $(LOCAL_CXX)),)
+  LOCAL_CXX := $($(my_prefix)CXX)
+endif
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_CXX := $(LOCAL_CXX)
+
+# TODO: support a mix of standard extensions so that this isn't necessary
+LOCAL_CPP_EXTENSION := $(strip $(LOCAL_CPP_EXTENSION))
+ifeq ($(LOCAL_CPP_EXTENSION),)
+  LOCAL_CPP_EXTENSION := .cpp
+endif
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_CPP_EXTENSION := $(LOCAL_CPP_EXTENSION)
+
+# Certain modules like libdl have to have symbols resolved at runtime and blow
+# up if --no-undefined is passed to the linker.
+ifeq ($(strip $(LOCAL_NO_DEFAULT_COMPILER_FLAGS)),)
+ifeq ($(strip $(LOCAL_ALLOW_UNDEFINED_SYMBOLS)),)
+  LOCAL_LDFLAGS := $(LOCAL_LDFLAGS) $($(my_prefix)NO_UNDEFINED_LDFLAGS)
+endif
+endif
+
+###########################################################
+## Define arm-vs-thumb-mode flags.
+###########################################################
+LOCAL_ARM_MODE := $(strip $(LOCAL_ARM_MODE))
+ifeq ($(TARGET_ARCH),arm)
+arm_objects_mode := $(if $(LOCAL_ARM_MODE),$(LOCAL_ARM_MODE),arm)
+normal_objects_mode := $(if $(LOCAL_ARM_MODE),$(LOCAL_ARM_MODE),thumb)
+
+# Read the values from something like TARGET_arm_CFLAGS or
+# TARGET_thumb_CFLAGS.  HOST_(arm|thumb)_CFLAGS values aren't
+# actually used (although they are usually empty).
+arm_objects_cflags := $($(my_prefix)$(arm_objects_mode)_CFLAGS)
+normal_objects_cflags := $($(my_prefix)$(normal_objects_mode)_CFLAGS)
+else
+arm_objects_mode :=
+normal_objects_mode :=
+arm_objects_cflags :=
+normal_objects_cflags :=
+endif
+
+###########################################################
+## Define per-module debugging flags.  Users can turn on
+## debugging for a particular module by setting DEBUG_MODULE_ModuleName
+## to a non-empty value in their environment or buildspec.mk,
+## and setting HOST_/TARGET_CUSTOM_DEBUG_CFLAGS to the
+## debug flags that they want to use.
+###########################################################
+ifdef DEBUG_MODULE_$(strip $(LOCAL_MODULE))
+  debug_cflags := $($(my_prefix)CUSTOM_DEBUG_CFLAGS)
+else
+  debug_cflags :=
+endif
+
+###########################################################
+## Stuff source generated from one-off tools
+###########################################################
+$(LOCAL_GENERATED_SOURCES): PRIVATE_MODULE := $(LOCAL_MODULE)
+
+ALL_GENERATED_SOURCES += $(LOCAL_GENERATED_SOURCES)
+
+
+###########################################################
+## Compile the .proto files to .cc and then to .o
+###########################################################
+proto_sources := $(filter %.proto,$(LOCAL_SRC_FILES))
+proto_generated_objects :=
+proto_generated_headers :=
+ifneq ($(proto_sources),)
+proto_sources_fullpath := $(addprefix $(LOCAL_PATH)/, $(proto_sources))
+proto_generated_cc_sources_dir := $(intermediates)/proto
+proto_generated_cc_sources := $(addprefix $(proto_generated_cc_sources_dir)/, \
+       $(patsubst %.proto,%.pb.cc,$(proto_sources_fullpath)))
+proto_generated_objects := $(patsubst %.cc,%.o, $(proto_generated_cc_sources))
+
+$(proto_generated_cc_sources): PRIVATE_PROTO_INCLUDES := $(TOP)
+$(proto_generated_cc_sources): PRIVATE_PROTO_CC_OUTPUT_DIR := $(proto_generated_cc_sources_dir)
+$(proto_generated_cc_sources): PRIVATE_PROTOC_FLAGS := $(LOCAL_PROTOC_FLAGS)
+$(proto_generated_cc_sources): $(proto_generated_cc_sources_dir)/%.pb.cc: %.proto $(PROTOC)
+       $(transform-proto-to-cc)
+
+proto_generated_headers := $(patsubst %.pb.cc,%.pb.h, $(proto_generated_cc_sources))
+$(proto_generated_headers): $(proto_generated_cc_sources_dir)/%.pb.h: $(proto_generated_cc_sources_dir)/%.pb.cc
+
+$(proto_generated_cc_sources): PRIVATE_ARM_MODE := $(normal_objects_mode)
+$(proto_generated_cc_sources): PRIVATE_ARM_CFLAGS := $(normal_objects_cflags)
+$(proto_generated_objects): $(proto_generated_cc_sources_dir)/%.o: $(proto_generated_cc_sources_dir)/%.cc
+       $(transform-$(PRIVATE_HOST)cpp-to-o)
+-include $(proto_generated_objects:%.o=%.P)
+
+LOCAL_C_INCLUDES += external/protobuf/src $(proto_generated_cc_sources_dir)
+LOCAL_CFLAGS += -DGOOGLE_PROTOBUF_NO_RTTI
+ifeq ($(LOCAL_PROTOC_OPTIMIZE_TYPE),full)
+LOCAL_STATIC_LIBRARIES += libprotobuf-cpp-2.3.0-full
+else
+LOCAL_STATIC_LIBRARIES += libprotobuf-cpp-2.3.0-lite
+endif
+endif
+
+
+###########################################################
+## YACC: Compile .y files to .cpp and the to .o.
+###########################################################
+
+yacc_sources := $(filter %.y,$(LOCAL_SRC_FILES))
+yacc_cpps := $(addprefix \
+       $(intermediates)/,$(yacc_sources:.y=$(LOCAL_CPP_EXTENSION)))
+yacc_headers := $(yacc_cpps:$(LOCAL_CPP_EXTENSION)=.h)
+yacc_objects := $(yacc_cpps:$(LOCAL_CPP_EXTENSION)=.o)
+
+ifneq ($(strip $(yacc_cpps)),)
+$(yacc_cpps): $(intermediates)/%$(LOCAL_CPP_EXTENSION): \
+               $(TOPDIR)$(LOCAL_PATH)/%.y \
+               $(lex_cpps) $(LOCAL_ADDITIONAL_DEPENDENCIES)
+       $(call transform-y-to-cpp,$(PRIVATE_CPP_EXTENSION))
+$(yacc_headers): $(intermediates)/%.h: $(intermediates)/%$(LOCAL_CPP_EXTENSION)
+
+$(yacc_objects): PRIVATE_ARM_MODE := $(normal_objects_mode)
+$(yacc_objects): PRIVATE_ARM_CFLAGS := $(normal_objects_cflags)
+$(yacc_objects): $(intermediates)/%.o: $(intermediates)/%$(LOCAL_CPP_EXTENSION)
+       $(transform-$(PRIVATE_HOST)cpp-to-o)
+endif
+
+###########################################################
+## LEX: Compile .l files to .cpp and then to .o.
+###########################################################
+
+lex_sources := $(filter %.l,$(LOCAL_SRC_FILES))
+lex_cpps := $(addprefix \
+       $(intermediates)/,$(lex_sources:.l=$(LOCAL_CPP_EXTENSION)))
+lex_objects := $(lex_cpps:$(LOCAL_CPP_EXTENSION)=.o)
+
+ifneq ($(strip $(lex_cpps)),)
+$(lex_cpps): $(intermediates)/%$(LOCAL_CPP_EXTENSION): \
+               $(TOPDIR)$(LOCAL_PATH)/%.l
+       $(transform-l-to-cpp)
+
+$(lex_objects): PRIVATE_ARM_MODE := $(normal_objects_mode)
+$(lex_objects): PRIVATE_ARM_CFLAGS := $(normal_objects_cflags)
+$(lex_objects): $(intermediates)/%.o: \
+               $(intermediates)/%$(LOCAL_CPP_EXTENSION) \
+               $(LOCAL_ADDITIONAL_DEPENDENCIES) \
+               $(yacc_headers)
+       $(transform-$(PRIVATE_HOST)cpp-to-o)
+endif
+
+###########################################################
+## C++: Compile .cpp files to .o.
+###########################################################
+
+# we also do this on host modules and sim builds, even though
+# it's not really arm, because there are files that are shared.
+cpp_arm_sources    := $(patsubst %$(LOCAL_CPP_EXTENSION).arm,%$(LOCAL_CPP_EXTENSION),$(filter %$(LOCAL_CPP_EXTENSION).arm,$(LOCAL_SRC_FILES)))
+cpp_arm_objects    := $(addprefix $(intermediates)/,$(cpp_arm_sources:$(LOCAL_CPP_EXTENSION)=.o))
+
+cpp_normal_sources := $(filter %$(LOCAL_CPP_EXTENSION),$(LOCAL_SRC_FILES))
+cpp_normal_objects := $(addprefix $(intermediates)/,$(cpp_normal_sources:$(LOCAL_CPP_EXTENSION)=.o))
+
+$(cpp_arm_objects):    PRIVATE_ARM_MODE := $(arm_objects_mode)
+$(cpp_arm_objects):    PRIVATE_ARM_CFLAGS := $(arm_objects_cflags)
+$(cpp_normal_objects): PRIVATE_ARM_MODE := $(normal_objects_mode)
+$(cpp_normal_objects): PRIVATE_ARM_CFLAGS := $(normal_objects_cflags)
+
+cpp_objects        := $(cpp_arm_objects) $(cpp_normal_objects)
+
+ifneq ($(strip $(cpp_objects)),)
+$(cpp_objects): $(intermediates)/%.o: \
+               $(TOPDIR)$(LOCAL_PATH)/%$(LOCAL_CPP_EXTENSION) \
+               $(yacc_cpps) $(proto_generated_headers) $(LOCAL_ADDITIONAL_DEPENDENCIES)
+       $(transform-$(PRIVATE_HOST)cpp-to-o)
+-include $(cpp_objects:%.o=%.P)
+endif
+
+###########################################################
+## C++: Compile generated .cpp files to .o.
+###########################################################
+
+gen_cpp_sources := $(filter %$(LOCAL_CPP_EXTENSION),$(LOCAL_GENERATED_SOURCES))
+gen_cpp_objects := $(gen_cpp_sources:%$(LOCAL_CPP_EXTENSION)=%.o)
+
+ifneq ($(strip $(gen_cpp_objects)),)
+# Compile all generated files as thumb.
+# TODO: support compiling certain generated files as arm.
+$(gen_cpp_objects): PRIVATE_ARM_MODE := $(normal_objects_mode)
+$(gen_cpp_objects): PRIVATE_ARM_CFLAGS := $(normal_objects_cflags)
+$(gen_cpp_objects): $(intermediates)/%.o: $(intermediates)/%$(LOCAL_CPP_EXTENSION) $(yacc_cpps) $(proto_generated_headers) $(LOCAL_ADDITIONAL_DEPENDENCIES)
+       $(transform-$(PRIVATE_HOST)cpp-to-o)
+-include $(gen_cpp_objects:%.o=%.P)
+endif
+
+###########################################################
+## S: Compile generated .S and .s files to .o.
+###########################################################
+
+gen_S_sources := $(filter %.S,$(LOCAL_GENERATED_SOURCES))
+gen_S_objects := $(gen_S_sources:%.S=%.o)
+
+ifneq ($(strip $(gen_S_sources)),)
+$(gen_S_objects): $(intermediates)/%.o: $(intermediates)/%.S $(LOCAL_ADDITIONAL_DEPENDENCIES)
+       $(transform-$(PRIVATE_HOST)s-to-o)
+-include $(gen_S_objects:%.o=%.P)
+endif
+
+gen_s_sources := $(filter %.s,$(LOCAL_GENERATED_SOURCES))
+gen_s_objects := $(gen_s_sources:%.s=%.o)
+
+ifneq ($(strip $(gen_s_objects)),)
+$(gen_s_objects): $(intermediates)/%.o: $(intermediates)/%.s $(LOCAL_ADDITIONAL_DEPENDENCIES)
+       $(transform-$(PRIVATE_HOST)s-to-o-no-deps)
+-include $(gen_s_objects:%.o=%.P)
+endif
+
+gen_asm_objects := $(gen_S_objects) $(gen_s_objects)
+
+###########################################################
+## C: Compile .c files to .o.
+###########################################################
+
+c_arm_sources    := $(patsubst %.c.arm,%.c,$(filter %.c.arm,$(LOCAL_SRC_FILES)))
+c_arm_objects    := $(addprefix $(intermediates)/,$(c_arm_sources:.c=.o))
+
+c_normal_sources := $(filter %.c,$(LOCAL_SRC_FILES))
+c_normal_objects := $(addprefix $(intermediates)/,$(c_normal_sources:.c=.o))
+
+$(c_arm_objects):    PRIVATE_ARM_MODE := $(arm_objects_mode)
+$(c_arm_objects):    PRIVATE_ARM_CFLAGS := $(arm_objects_cflags)
+$(c_normal_objects): PRIVATE_ARM_MODE := $(normal_objects_mode)
+$(c_normal_objects): PRIVATE_ARM_CFLAGS := $(normal_objects_cflags)
+
+c_objects        := $(c_arm_objects) $(c_normal_objects)
+
+ifneq ($(strip $(c_objects)),)
+$(c_objects): $(intermediates)/%.o: $(TOPDIR)$(LOCAL_PATH)/%.c $(yacc_cpps) $(proto_generated_headers) $(LOCAL_ADDITIONAL_DEPENDENCIES)
+       $(transform-$(PRIVATE_HOST)c-to-o)
+-include $(c_objects:%.o=%.P)
+endif
+
+###########################################################
+## C: Compile generated .c files to .o.
+###########################################################
+
+gen_c_sources := $(filter %.c,$(LOCAL_GENERATED_SOURCES))
+gen_c_objects := $(gen_c_sources:%.c=%.o)
+
+ifneq ($(strip $(gen_c_objects)),)
+# Compile all generated files as thumb.
+# TODO: support compiling certain generated files as arm.
+$(gen_c_objects): PRIVATE_ARM_MODE := $(normal_objects_mode)
+$(gen_c_objects): PRIVATE_ARM_CFLAGS := $(normal_objects_cflags)
+$(gen_c_objects): $(intermediates)/%.o: $(intermediates)/%.c $(yacc_cpps) $(proto_generated_headers) $(LOCAL_ADDITIONAL_DEPENDENCIES)
+       $(transform-$(PRIVATE_HOST)c-to-o)
+-include $(gen_c_objects:%.o=%.P)
+endif
+
+###########################################################
+## ObjC: Compile .m files to .o
+###########################################################
+
+objc_sources := $(filter %.m,$(LOCAL_SRC_FILES))
+objc_objects := $(addprefix $(intermediates)/,$(objc_sources:.m=.o))
+
+ifneq ($(strip $(objc_objects)),)
+$(objc_objects): $(intermediates)/%.o: $(TOPDIR)$(LOCAL_PATH)/%.m $(yacc_cpps) $(proto_generated_headers) $(PRIVATE_ADDITIONAL_DEPENDENCIES)
+       $(transform-$(PRIVATE_HOST)m-to-o)
+-include $(objc_objects:%.o=%.P)
+endif
+
+###########################################################
+## AS: Compile .S files to .o.
+###########################################################
+
+asm_sources_S := $(filter %.S,$(LOCAL_SRC_FILES))
+asm_objects_S := $(addprefix $(intermediates)/,$(asm_sources_S:.S=.o))
+
+ifneq ($(strip $(asm_objects_S)),)
+$(asm_objects_S): $(intermediates)/%.o: $(TOPDIR)$(LOCAL_PATH)/%.S $(LOCAL_ADDITIONAL_DEPENDENCIES)
+       $(transform-$(PRIVATE_HOST)s-to-o)
+-include $(asm_objects_S:%.o=%.P)
+endif
+
+asm_sources_s := $(filter %.s,$(LOCAL_SRC_FILES))
+asm_objects_s := $(addprefix $(intermediates)/,$(asm_sources_s:.s=.o))
+
+ifneq ($(strip $(asm_objects_s)),)
+$(asm_objects_s): $(intermediates)/%.o: $(TOPDIR)$(LOCAL_PATH)/%.s $(LOCAL_ADDITIONAL_DEPENDENCIES)
+       $(transform-$(PRIVATE_HOST)s-to-o-no-deps)
+-include $(asm_objects_s:%.o=%.P)
+endif
+
+asm_objects := $(asm_objects_S) $(asm_objects_s)
+
+
+###########################################################
+## Common object handling.
+###########################################################
+
+# some rules depend on asm_objects being first.  If your code depends on
+# being first, it's reasonable to require it to be assembly
+all_objects := \
+       $(asm_objects) \
+       $(cpp_objects) \
+       $(gen_cpp_objects) \
+       $(gen_asm_objects) \
+       $(c_objects) \
+       $(gen_c_objects) \
+       $(yacc_objects) \
+       $(lex_objects) \
+       $(proto_generated_objects) \
+       $(addprefix $(TOPDIR)$(LOCAL_PATH)/,$(LOCAL_PREBUILT_OBJ_FILES))
+
+LOCAL_C_INCLUDES += $(TOPDIR)$(LOCAL_PATH) $(intermediates) $(base_intermediates)
+
+ifndef LOCAL_NDK_VERSION
+  LOCAL_C_INCLUDES += $(JNI_H_INCLUDE)
+endif
+
+$(all_objects) : | $(LOCAL_GENERATED_SOURCES)
+ALL_C_CPP_ETC_OBJECTS += $(all_objects)
+
+###########################################################
+## Copy headers to the install tree
+###########################################################
+include $(BUILD_COPY_HEADERS)
+
+###########################################################
+# Standard library handling.
+#
+# On the target, we compile with -nostdlib, so we must add in the
+# default system shared libraries, unless they have requested not
+# to by supplying a LOCAL_SYSTEM_SHARED_LIBRARIES value.  One would
+# supply that, for example, when building libc itself.
+###########################################################
+ifdef LOCAL_IS_HOST_MODULE
+  ifeq ($(LOCAL_SYSTEM_SHARED_LIBRARIES),none)
+    LOCAL_SYSTEM_SHARED_LIBRARIES :=
+  endif
+else
+  ifeq ($(LOCAL_SYSTEM_SHARED_LIBRARIES),none)
+    LOCAL_SYSTEM_SHARED_LIBRARIES := $($(my_prefix)DEFAULT_SYSTEM_SHARED_LIBRARIES)
+  endif
+endif
+
+# Logging used to be part of libcutils (target) and libutils (sim);
+# hack modules that use those other libs to also include liblog.
+# All of this complexity is to make sure that liblog only appears
+# once, and appears just before libcutils or libutils on the link
+# line.
+# TODO: remove this hack and change all modules to use liblog
+# when necessary.
+define insert-liblog
+  $(if $(filter liblog,$(1)),$(1), \
+    $(if $(filter libcutils,$(1)), \
+      $(patsubst libcutils,liblog libcutils,$(1)) \
+     , \
+      $(patsubst libutils,liblog libutils,$(1)) \
+     ) \
+   )
+endef
+ifneq (,$(filter libcutils libutils,$(LOCAL_SHARED_LIBRARIES)))
+  LOCAL_SHARED_LIBRARIES := $(call insert-liblog,$(LOCAL_SHARED_LIBRARIES))
+endif
+ifneq (,$(filter libcutils libutils,$(LOCAL_STATIC_LIBRARIES)))
+  LOCAL_STATIC_LIBRARIES := $(call insert-liblog,$(LOCAL_STATIC_LIBRARIES))
+endif
+ifneq (,$(filter libcutils libutils,$(LOCAL_WHOLE_STATIC_LIBRARIES)))
+  LOCAL_WHOLE_STATIC_LIBRARIES := $(call insert-liblog,$(LOCAL_WHOLE_STATIC_LIBRARIES))
+endif
+
+###########################################################
+# The list of libraries that this module will link against are in
+# these variables.  Each is a list of bare module names like "libc libm".
+#
+# LOCAL_SHARED_LIBRARIES
+# LOCAL_STATIC_LIBRARIES
+# LOCAL_WHOLE_STATIC_LIBRARIES
+#
+# We need to convert the bare names into the dependencies that
+# we'll use for LOCAL_BUILT_MODULE and LOCAL_INSTALLED_MODULE.
+# LOCAL_BUILT_MODULE should depend on the BUILT versions of the
+# libraries, so that simply building this module doesn't force
+# an install of a library.  Similarly, LOCAL_INSTALLED_MODULE
+# should depend on the INSTALLED versions of the libraries so
+# that they get installed when this module does.
+###########################################################
+# NOTE:
+# WHOLE_STATIC_LIBRARIES are libraries that are pulled into the
+# module without leaving anything out, which is useful for turning
+# a collection of .a files into a .so file.  Linking against a
+# normal STATIC_LIBRARY will only pull in code/symbols that are
+# referenced by the module. (see gcc/ld's --whole-archive option)
+###########################################################
+
+# Get the list of BUILT libraries, which are under
+# various intermediates directories.
+so_suffix := $($(my_prefix)SHLIB_SUFFIX)
+a_suffix := $($(my_prefix)STATIC_LIB_SUFFIX)
+
+ifdef LOCAL_NDK_VERSION
+built_shared_libraries := \
+    $(addprefix $($(my_prefix)OUT_INTERMEDIATE_LIBRARIES)/, \
+      $(addsuffix $(so_suffix), \
+        $(LOCAL_SHARED_LIBRARIES)))
+
+# Get the list of INSTALLED libraries.  Strip off the various
+# intermediates directories and point to the common lib dirs.
+installed_shared_libraries := \
+    $(addprefix $($(my_prefix)OUT_SHARED_LIBRARIES)/, \
+      $(notdir $(built_shared_libraries)))
+
+my_system_shared_libraries_fullpath := $(addprefix $(my_ndk_version_root)/usr/lib/, \
+    $(addsuffix $(so_suffix), $(LOCAL_SYSTEM_SHARED_LIBRARIES)))
+
+built_shared_libraries += $(my_system_shared_libraries_fullpath)
+LOCAL_SHARED_LIBRARIES += $(LOCAL_SYSTEM_SHARED_LIBRARIES)
+else
+LOCAL_SHARED_LIBRARIES += $(LOCAL_SYSTEM_SHARED_LIBRARIES)
+built_shared_libraries := \
+    $(addprefix $($(my_prefix)OUT_INTERMEDIATE_LIBRARIES)/, \
+      $(addsuffix $(so_suffix), \
+        $(LOCAL_SHARED_LIBRARIES)))
+
+installed_shared_libraries := \
+    $(addprefix $($(my_prefix)OUT_SHARED_LIBRARIES)/, \
+      $(notdir $(built_shared_libraries)))
+endif
+
+built_static_libraries := \
+    $(foreach lib,$(LOCAL_STATIC_LIBRARIES), \
+      $(call intermediates-dir-for, \
+        STATIC_LIBRARIES,$(lib),$(LOCAL_IS_HOST_MODULE))/$(lib)$(a_suffix))
+
+built_whole_libraries := \
+    $(foreach lib,$(LOCAL_WHOLE_STATIC_LIBRARIES), \
+      $(call intermediates-dir-for, \
+        STATIC_LIBRARIES,$(lib),$(LOCAL_IS_HOST_MODULE))/$(lib)$(a_suffix))
+
+# We don't care about installed static libraries, since the
+# libraries have already been linked into the module at that point.
+# We do, however, care about the NOTICE files for any static
+# libraries that we use. (see notice_files.make)
+
+installed_static_library_notice_file_targets := \
+    $(foreach lib,$(LOCAL_STATIC_LIBRARIES) $(LOCAL_WHOLE_STATIC_LIBRARIES), \
+      NOTICE-$(if $(LOCAL_IS_HOST_MODULE),HOST,TARGET)-STATIC_LIBRARIES-$(lib))
+
+###########################################################
+# Rule-specific variable definitions
+###########################################################
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_YACCFLAGS := $(LOCAL_YACCFLAGS)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_ASFLAGS := $(LOCAL_ASFLAGS)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_CFLAGS := $(LOCAL_CFLAGS)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_CPPFLAGS := $(LOCAL_CPPFLAGS)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_DEBUG_CFLAGS := $(debug_cflags)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_C_INCLUDES := $(LOCAL_C_INCLUDES)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_LDFLAGS := $(LOCAL_LDFLAGS)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_LDLIBS := $(LOCAL_LDLIBS)
+
+# this is really the way to get the files onto the command line instead
+# of using $^, because then LOCAL_ADDITIONAL_DEPENDENCIES doesn't work
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_ALL_SHARED_LIBRARIES := $(built_shared_libraries)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_ALL_STATIC_LIBRARIES := $(built_static_libraries)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_ALL_WHOLE_STATIC_LIBRARIES := $(built_whole_libraries)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_ALL_OBJECTS := $(all_objects)
+
+###########################################################
+# Define library dependencies.
+###########################################################
+# all_libraries is used for the dependencies on LOCAL_BUILT_MODULE.
+all_libraries := \
+    $(built_shared_libraries) \
+    $(built_static_libraries) \
+    $(built_whole_libraries)
+
+# Make LOCAL_INSTALLED_MODULE depend on the installed versions of the
+# libraries so they get installed along with it.  We don't need to
+# rebuild it when installing it, though, so this can be an order-only
+# dependency.
+$(LOCAL_INSTALLED_MODULE): | $(installed_shared_libraries)
+
+# Also depend on the notice files for any static libraries that
+# are linked into this module.  This will force them to be installed
+# when this module is.
+$(LOCAL_INSTALLED_MODULE): | $(installed_static_library_notice_file_targets)
diff --git a/build/core/build-system.html b/build/core/build-system.html
new file mode 100644 (file)
index 0000000..e547185
--- /dev/null
@@ -0,0 +1,954 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<!--
+  A lot of people read this document template.  Please keep it clean:
+
+   - keep the document xhtml-compliant, as many people use validating editors
+   - check your edits for typos, spelling errors, and questionable grammar
+   - prefer css styles to formatting tags like <font>, <tt>, etc.
+   - keep it human-readable and human-editable in a plain text editor:
+     - strive to keep lines wrapped at 80 columns, unless a link prevents it
+     - use plenty of whitespace
+     - try to pretty-format (wrt nesting and indenting) any hairy html
+   - check your inline javascript for errors using the javascript console
+   
+  Your readers will be very appreciative.
+-->
+
+<head>
+  <title>Android Build System</title>
+
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+  <link href="../android.css" type="text/css" rel="stylesheet" />
+
+<!-- commenting out so the xhtml validator doesn't whine about < and &&;
+     the browser should still find the script tag. -->
+<script language="JavaScript1.2" type="text/javascript">
+<!--
+function highlight(name) {
+  if (document.getElementsByTagName) {
+    tags              = [ 'span', 'div', 'tr', 'td' ];
+    for (i in tags) {
+      elements        = document.getElementsByTagName(tags[i]);
+      if (elements) {
+        for (j = 0; j < elements.length; j++) {
+          elementName = elements[j].getAttribute("class");
+          if (elementName == name) {
+            elements[j].style.backgroundColor = "#C0F0C0";
+          } else if (elementName && elementName.indexOf("rev") == 0) {
+            elements[j].style.backgroundColor = "#FFFFFF";
+          }
+        }
+      }
+    }
+  }
+}
+//-->
+  </script>
+  <!-- this style sheet is for the style of the toc -->
+  <link href="toc.css" type="text/css" rel="stylesheet" />
+
+  <style type="text/css">
+    .warning {
+        border: 1px solid red;
+        padding: 8px;
+        color: red;
+    }
+    pre.prettyprint {
+        margin-top: 0;
+    }
+    li {
+        margin-top: 8px;
+    }
+  </style>
+</head>
+
+<body onload="prettyPrint()">
+
+<h1><a name="My_Project_" />Android Build System</h1>
+
+<!-- Status is one of: Draft, Current, Needs Update, Obsolete -->
+<p style="text-align:center">
+  <strong>Status:</strong> <em>Draft </em> &nbsp;
+  <small>(as of May 18, 2006)</small>
+</p>
+
+<p><b>Contents</b></p>
+<!-- this div expands out to a list of contents based on the H2 and H3 headings.
+Believe it! -->
+ <div id="nav"  class="nav-2-levels"></div>
+
+<h2>Objective</h2>
+<p>The primary goals of reworking the build system are (1) to make dependencies
+work more reliably, so that when files need to rebuilt, they are, and (2) to
+improve performance of the build system so that unnecessary modules are not
+rebuilt, and so doing a top-level build when little or nothing needs to be done
+for a build takes as little time as possible.</p>
+
+<h2>Principles and Use Cases and Policy</h2>
+<p>Given the above objective, these are the overall principles and use cases
+that we will support.  This is not an exhaustive list.</p>
+<h3>Multiple Targets</h3>
+<p>It needs to be possible to build the Android platform for multiple targets.
+This means:</p>
+<ul>
+    <li>The build system will support building tools for the host platform,
+    both ones that are used in the build process itself, and developer tools
+    like the simulator.</li>
+    <li>The build system will need to be able to build tools on Linux
+    (definitely Goobuntu and maybe Grhat), MacOS, and to some degree on
+    Windows.</li>
+    <li>The build system will need to be able to build the OS on Linux, and in
+    the short-term, MacOS.  Note that this is a conscious decision to stop
+    building the OS on Windows.  We are going to rely on the emulator there
+    and not attempt to use the simulator.  This is a requirement change now
+    that the emulator story is looking brighter.</li>
+</ul>
+<h3>Non-Recursive Make</h3>
+<p>To achieve the objectives, the build system will be rewritten to use make
+non-recursively.  For more background on this, read <a href="http://aegis.sourceforge.net/auug97.pdf">Recursive Make Considered Harmful</a>.  For those that don't
+want PDF, here is the
+<a href="http://72.14.203.104/search?q=cache:HwuX7YF2uBIJ:aegis.sourceforge.net/auug97.pdf&hl=en&gl=us&ct=clnk&cd=2&client=firefox">Google translated version</a>.
+<h3>Rapid Compile-Test Cycles</h3>
+<p>When developing a component, for example a C++ shared library, it must be
+possible to easily rebuild just that component, and not have to wait more than a
+couple seconds for dependency checks, and not have to wait for unneeded
+components to be built.</p>
+<h3>Both Environment and Config File Based Settings</h3>
+<p>To set the target, and other options, some people on the team like to have a
+configuration file in a directory so they do not have an environment setup
+script to run, and others want an environment setup script to run so they can
+run builds in different terminals on the same tree, or switch back and forth
+in one terminal.  We will support both.</p>
+<h3>Object File Directory / make clean</h3>
+<p>Object files and other intermediate files will be generated into a directory
+that is separate from the source tree.  The goal is to have make clean be
+"rm -rf <obj>" in the tree root directory.  The primary goals of
+this are to simplify searching the source tree, and to make "make clean" more
+reliable.</p>
+
+<h3>SDK</h3>
+<p>The SDK will be a tarball that will allow non-OS-developers to write apps.
+The apps will actually be built by first building the SDK, and then building
+the apps against that SDK.  This will hopefully (1) make writing apps easier
+for us, because we won't have to rebuild the OS as much, and we can use the
+standard java-app development tools, and (2) allow us to dog-food the SDK, to
+help ensure its quality.  Cedric has suggested (and I agree) that apps built
+from the SDK should be built with ant.  Stay tuned for more details as we
+figure out exactly how this will work.</p>
+
+<h3>Dependecies</h3>
+<p>Dependencies should all be automatic.  Unless there is a custom tool involved
+(e.g. the webkit has several), the dependencies for shared and static libraries,
+.c, .cpp, .h, .java, java libraries, etc., should all work without intervention
+in the Android.mk file.</p>
+
+<h3>Hiding command lines</h3>
+<p>The default of the build system will be to hide the command lines being
+executed for make steps.  It will be possible to override this by specifying
+the showcommands pseudo-target, and possibly by setting an environment
+variable.</p>
+
+<h3>Wildcard source files</h3>
+<p>Wildcarding source file will be discouraged.  It may be useful in some
+scenarios.  The default <code>$(wildcard *)</code> will not work due to the
+current directory being set to the root of the build tree.<p>
+
+<h3>Multiple targets in one directory</h3>
+<p>It will be possible to generate more than one target from a given
+subdirectory.  For example, libutils generates a shared library for the target
+and a static library for the host.</p>
+
+<h3>Makefile fragments for modules</h3>
+<p><b>Android.mk</b> is the standard name for the makefile fragments that
+control the building of a given module.  Only the top directory should
+have a file named "Makefile".</p>
+
+<h3>Use shared libraries</h3>
+<p>Currently, the simulator is not built to use shared libraries.  This should
+be fixed, and now is a good time to do it.  This implies getting shared
+libraries to work on Mac OS.</p>
+
+
+<h2>Nice to Have</h2>
+
+<p>These things would be nice to have, and this is a good place to record them,
+however these are not promises.</p>
+
+<h3>Simultaneous Builds</h3>
+<p>The hope is to be able to do two builds for different combos in the same
+tree at the same time, but this is a stretch goal, not a requirement.
+Doing two builds in the same tree, not at the same time must work.  (update:
+it's looking like we'll get the two builds at the same time working)</p>
+
+<h3>Deleting headers (or other dependecies)</h3>
+<p>Problems can arise if you delete a header file that is referenced in
+".d" files.  The easy way to deal with this is "make clean".  There
+should be a better way to handle it. (from fadden)</p>
+<p>One way of solving this is introducing a dependency on the directory.  The
+problem is that this can create extra dependecies and slow down the build.
+It's a tradeoff.</p>
+
+<h3>Multiple builds</h3>
+<p>General way to perform builds across the set of known platforms.  This
+would make it easy to perform multiple platform builds when testing a
+change, and allow a wide-scale "make clean".  Right now the buildspec.mk
+or environment variables need to be updated before each build. (from fadden)</p>
+
+<h3>Aftermarket Locales and Carrier</h3>
+<p>We will eventually need to add support for creating locales and carrier
+customizations to the SDK, but that will not be addressed right now.</p>
+
+
+<h2><a id="usage"/>Usage</h2>
+<p>You've read (or scrolled past) all of the motivations for this build system,
+and you want to know how to use it.  This is the place.</p>
+
+<h3>Your first build</h3>
+<p>The <a href="../building.html">Building</a> document describes how do do
+builds.</p>
+
+<h3>build/envsetup.sh functions</h3>
+If you source the file build/envsetup.sh into your bash environment,
+<code>. build/envsetup.sh</code>you'll get a few helpful shell functions:
+
+<ul>
+<li><b>printconfig</b> - Prints the current configuration as set by the
+lunch and choosecombo commands.</li>
+<li><b>m</b> - Runs <code>make</code> from the top of the tree.  This is
+useful because you can run make from within subdirectories.  If you have the
+<code>TOP</code> environment variable set, it uses that.  If you don't, it looks
+up the tree from the current directory, trying to find the top of the tree.</li>
+<li><b>croot</b> - <code>cd</code> to the top of the tree.</li>
+<li><b>sgrep</b> - grep for the regex you provide in all .c, .cpp, .h, .java,
+and .xml files below the current directory.</li>
+</ul>
+
+<h3>Build flavors/types</h3>
+<p>
+When building for a particular product, it's often useful to have minor
+variations on what is ultimately the final release build.  These are the
+currently-defined "flavors" or "types" (we need to settle on a real name
+for these).
+</p>
+
+<table border=1>
+<tr>
+    <td>
+        <code>eng<code>
+    </td>
+    <td>
+        This is the default flavor. A plain "<code>make</code>" is the
+        same as "<code>make eng</code>".  <code>droid</code> is an alias
+        for <code>eng</code>.
+        <ul>
+        <li>Installs modules tagged with: <code>eng</code>, <code>debug</code>,
+            <code>shell_</code>$(TARGET_SHELL),
+            <code>user</code>, and/or <code>development</code>.
+        <li>Installs non-APK modules that have no tags specified.
+        <li>Installs APKs according to the product definition files, in
+            addition to tagged APKs.
+        <li><code>ro.secure=0</code>
+        <li><code>ro.debuggable=1</code>
+        <li><code>ro.kernel.android.checkjni=1</code>
+        <li><code>adb</code> is enabled by default.
+    </td>
+</tr>
+<tr>
+    <td>
+        <code>user<code>
+    </td>
+    <td>
+        "<code>make user</code>"
+        <p>
+        This is the flavor intended to be the final release bits.
+        <ul>
+        <li>Installs modules tagged with <code>shell_</code>$(TARGET_SHELL) and <code>user</code>.
+        <li>Installs non-APK modules that have no tags specified.
+        <li>Installs APKs according to the product definition files; tags
+            are ignored for APK modules.
+        <li><code>ro.secure=1</code>
+        <li><code>ro.debuggable=0</code>
+        <li><code>adb</code> is disabled by default.
+    </td>
+</tr>
+<tr>
+    <td>
+        <code>userdebug<code>
+    </td>
+    <td>
+        "<code>make userdebug</code>"
+        <p>
+        The same as <code>user</code>, except:
+        <ul>
+        <li>Also installs modules tagged with <code>debug</code>.
+        <li><code>ro.debuggable=1</code>
+        <li><code>adb</code> is enabled by default.
+    </td>
+</tr>
+</table>
+
+<p>
+If you build one flavor and then want to build another, you should run
+"<code>make installclean</code>" between the two makes to guarantee that
+you don't pick up files installed by the previous flavor.  "<code>make
+clean</code>" will also suffice, but it takes a lot longer.
+</p>
+
+
+<h3>More pseudotargets</h3>
+<p>Sometimes you want to just build one thing.  The following pseudotargets are
+there for your convenience:</p>
+
+<ul>
+<li><b>droid</b> - <code>make droid</code> is the normal build.  This target
+is here because the default target has to have a name.</li>
+<li><b>all</b> - <code>make all</code> builds everything <code>make
+droid</code> does, plus everything whose <code>LOCAL_MODULE_TAGS</code> do not
+include the "droid" tag.  The build server runs this to make sure
+that everything that is in the tree and has an Android.mk builds.</li>
+<li><b>clean-$(LOCAL_MODULE)</b> and <b>clean-$(LOCAL_PACKAGE_NAME)</b> - 
+Let you selectively clean one target.  For example, you can type
+<code>make clean-libutils</code> and it will delete libutils.so and all of the
+intermediate files, or you can type <code>make clean-Home</code> and it will
+clean just the Home app.</li>
+<li><b>clean</b> - <code>make clean</code> deletes all of the output and
+intermediate files for this configuration.  This is the same as <code>rm -rf
+out/&lt;configuration&gt;/</code></li>
+<li><b>clobber</b> - <code>make clobber</code> deletes all of the output
+and intermediate files for all configurations.  This is the same as
+<code>rm -rf out/</code>.</li>
+<li><b>dataclean</b> - <code>make dataclean</code> deletes contents of the data 
+directory inside the current combo directory.  This is especially useful on the
+simulator and emulator, where the persistent data remains present between 
+builds.</li>
+<li><b>showcommands</b> - <code>showcommands</code> is a modifier target
+which causes the build system to show the actual command lines for the build
+steps, instead of the brief descriptions.  Most people don't like seeing the
+actual commands, because they're quite long and hard to read, but if you need
+to for debugging purposes, you can add <code>showcommands</code> to the list
+of targets you build.  For example <code>make showcommands</code> will build
+the default android configuration, and <code>make runtime showcommands</code>
+will build just the runtime, and targets that it depends on, while displaying
+the full command lines.  Please note that there are a couple places where the
+commands aren't shown here.  These are considered bugs, and should be fixed,
+but they're often hard to track down.  Please let
+<a href="mailto:android-build-team">android-build-team</a> know if you find
+any.</li>
+<li><b>LOCAL_MODULE</b> - Anything you specify as a <code>LOCAL_MODULE</code>
+in an Android.mk is made into a pseudotarget.  For example, <code>make
+runtime</code> might be shorthand for <code>make
+out/linux-x86-debug/system/bin/runtime</code> (which would work), and
+<code>make libkjs</code> might be shorthand for <code>make
+out/linux-x86-debug/system/lib/libkjs.so</code> (which would also work).</li>
+<li><b>targets</b> - <code>make targets</code> will print a list of all of
+the LOCAL_MODULE names you can make.</li>
+</ul>
+
+<h3><a name="templates"/>How to add another component to the build - Android.mk templates</h3>
+<p>You have a new library, a new app, or a new executable.  For each of the
+common types of modules, there is a corresponding file in the templates
+directory.  It will usually be enough to copy one of these, and fill in your
+own values.  Some of the more esoteric values are not included in the
+templates, but are instead just documented here, as is the documentation
+on using custom tools to generate files.</p>
+<p>Mostly, you can just look for the TODO comments in the templates and do
+what it says.  Please remember to delete the TODO comments when you're done
+to keep the files clean.  The templates have minimal documentation in them,
+because they're going to be copied, and when that gets stale, the copies just
+won't get updated.  So read on...</p>
+
+<h4>Apps</h4>
+<p>Use the <code>templates/apps</code> file.</p>
+<p>This template is pretty self-explanitory.  See the variables below for more
+details.</p>
+
+<h4>Java Libraries</h4>
+<p>Use the <code>templates/java_library</code> file.</p>
+<p>The interesting thing here is the value of LOCAL_MODULE, which becomes
+the name of the jar file.  (Actually right now, we're not making jar files yet,
+just directories of .class files,  but the directory is named according to
+what you put in LOCAL_MODULE).  This name will be what goes in the 
+LOCAL_JAVA_LIBRARIES variable in modules that depend on your java library.</p>
+
+<h4>C/C++ Executables</h4>
+<p>Use the <code>templates/executable</code> file, or the
+<code>templates/executable_host</code> file.</p>
+<p>This template has a couple extra options that you usually don't need.
+Please delete the ones you don't need, and remove the TODO comments.  It makes
+the rest of them easier to read, and you can always refer back to the templates
+if you need them again later.</p>
+<p>By default, on the target these are built into /system/bin, and on the
+host, they're built into <combo>/host/bin.  These can be overridden by setting
+<code>LOCAL_MODULE_PATH</code>.  See
+<a href="#moving-targets">Putting targets elsewhere</a>
+for more.</p>
+
+<h4>Shared Libraries</h4>
+<p>Use the <code>templates/shared_library</code> file, or the
+<code>templates/shared_library_host</code> file.</p>
+<p>Remember that on the target, we use shared libraries, and on the host,
+we use static libraries, since executable size isn't as big an issue, and it
+simplifies distribution in the SDK.</p>
+
+<h4>Static Libraries</h4>
+<p>Use the <code>templates/static_library</code> file, or the
+<code>templates/static_library_host</code> file.</p>
+<p>Remember that on the target, we use shared libraries, and on the host,
+we use static libraries, since executable size isn't as big an issue, and it
+simplifies distribution in the SDK.</p>
+
+<h4><a name="custom-tools"/>Using Custom Tools</h4>
+<p>If you have a tool that generates source files for you, it's possible
+to have the build system get the dependencies correct for it.  Here are
+a couple of examples.  <code>$@</code> is the make built-in variable for
+"the current target." The <font color=red>red</font> parts are the parts you'll
+need to change.</p>
+
+<p>You need to put this after you have declared <code>LOCAL_PATH</code> and
+<code>LOCAL_MODULE</code>, because the <code>$(local-intermediates-dir)</code>
+and <code>$(local-host-intermediates-dir)</code> macros use these variables
+to determine where to put the files.
+
+<h5>Example 1</h5>
+<p>Here, there is one generated file, called
+chartables.c, which doesn't depend on anything.  And is built by the tool
+built to $(HOST_OUT_EXECUTABLES)/dftables.  Note on the second to last line
+that a dependency is created on the tool.</p>
+<pre>
+intermediates:= $(local-intermediates-dir)
+GEN := $(intermediates)/<font color=red>chartables.c</font>
+$(GEN): PRIVATE_CUSTOM_TOOL = <font color=red>$(HOST_OUT_EXECUTABLES)/dftables $@</font>
+$(GEN): <font color=red>$(HOST_OUT_EXECUTABLES)/dftables</font>
+       $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+</pre>
+
+<h5>Example 2</h5>
+<p>Here as a hypothetical example, we use use cat as if it were to transform
+a file.  Pretend that it does something useful.  Note how we use a
+target-specific variable called PRIVATE_INPUT_FILE to store the name of the
+input file.</p>
+<pre>
+intermediates:= $(local-intermediates-dir)
+GEN := $(intermediates)/<font color=red>file.c</font>
+$(GEN): PRIVATE_INPUT_FILE := $(LOCAL_PATH)/<font color=red>input.file</font>
+$(GEN): PRIVATE_CUSTOM_TOOL = <font color=red>cat $(PRIVATE_INPUT_FILE) &gt; $@</font>
+$(GEN): <font color=red>$(LOCAL_PATH)/file.c</font>
+       $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+</pre>
+
+<h5>Example 3</h5>
+<p>If you have several files that are all similar in
+name, and use the same tool, you can combine them.  (here the *.lut.h files are
+the generated ones, and the *.cpp files are the input files)</p>
+<pre>
+intermediates:= $(local-intermediates-dir)
+GEN := $(addprefix $(intermediates)<font color=red>/kjs/, \
+            array_object.lut.h \
+            bool_object.lut.h \</font>
+        )
+$(GEN): PRIVATE_CUSTOM_TOOL = <font color=red>perl libs/WebKitLib/WebKit/JavaScriptCore/kjs/create_hash_table $< -i > $@</font>
+$(GEN): $(intermediates)/<font color=red>%.lut.h</font> : $(LOCAL_PATH)/<font color=red>%.cpp</font>
+       $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+</pre>
+
+<h3><a name="platform-specific"/>Platform specific conditionals</h3>
+<p>Sometimes you need to set flags specifically for different platforms.  Here
+is a list of which values the different build-system defined variables will be
+set to and some examples.</p>
+<p>For a device build, <code>TARGET_OS</code> is <code>linux</code> (we're using
+linux!), and <code>TARGET_ARCH</code> is <code>arm</code>.</p>
+<p>For a simulator build, <code>TARGET_OS</code> and <code>TARGET_ARCH</code>
+are set to the same as <code>HOST_OS</code> and <code>HOST_ARCH</code> are
+on your platform.  <code>TARGET_PRODUCT</code> is the name of the target
+hardware/product you are building for.  The value <code>sim</code> is used
+for the simulator.  We haven't thought through the full extent of customization
+that will happen here, but likely there will be additional UI configurations
+specified here as well.</p>
+<table cellspacing=25>
+<tr>
+    <td valign=top align=center>
+        <b>HOST_OS</b><br/>
+        linux<br/>
+        darwin<br/>
+        (cygwin)
+    </td>
+    <td valign=top align=center>
+        <b>HOST_ARCH</b><br/>
+        x86
+    </td>
+    <td valign=top align=center>
+        <b>HOST_BUILD_TYPE</b><br/>
+        release<br/>
+        debug
+    </td>
+</tr>
+<tr>
+    <td valign=top align=center>
+        <b>TARGET_OS</b><br/>
+        linux<br/>
+        darwin<br/>
+        (cygwin)
+    </td>
+    <td valign=top align=center>
+        <b>TARGET_ARCH</b><br/>
+        arm<br/>
+        x86
+    </td>
+    <td valign=top align=center>
+        <b>TARGET_BUILD_TYPE</b><br/>
+        release<br/>
+        debug
+    </td>
+    <td valign=top align=center>
+        <b>TARGET_PRODUCT</b><br/>
+        sim<br/>
+        dream<br/>
+        sooner
+    </td>
+</tr>
+</table>
+
+<h4>TARGET_SIMULATOR</h4>
+<p>If we're building the simulator, as opposed to the arm or emulator builds,
+<code>TARGET_SIMULATOR</code> will be set to <code>true</code>.
+
+<h4>Some Examples</h4>
+<pre>ifeq ($(TARGET_SIMULATOR),true)
+LOCAL_CFLAGS += -DSIMULATOR
+endif
+
+ifeq ($(TARGET_BUILD_TYPE),release)
+LOCAL_CFLAGS += -DNDEBUG=1
+endif
+
+# from libutils
+ifeq ($(TARGET_OS),linux)
+# Use the futex based mutex and condition variable
+# implementation from android-arm because it's shared mem safe
+LOCAL_SRC_FILES += futex_synchro.c
+LOCAL_LDLIBS += -lrt -ldl
+endif
+
+</pre>
+
+
+<h3><a name="moving-modules"/>Putting modules elsewhere</h3>
+<p>If you have modules that normally go somewhere, and you need to have them
+build somewhere else, read this.  One use of this is putting files on
+the root filesystem instead of where they normally go in /system. Add these
+lines to your Android.mk:</p>
+<pre>
+LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
+LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
+</pre>
+<p>For executables and libraries, you need to also specify a
+<code>LOCAL_UNSTRIPPED_PATH</code> location, because on target builds, we keep
+the unstripped executables so GDB can find the symbols.</code>
+<p>Look in <code>config/envsetup.make</code> for all of the variables defining
+places to build things.</p>
+<p>FYI: If you're installing an executable to /sbin, you probably also want to
+set <code>LOCAL_FORCE_STATIC_EXCUTABLE := true</code> in your Android.mk, which
+will force the linker to only accept static libraries.</p>
+
+
+<h3>Android.mk variables</h3>
+<p>These are the variables that you'll commonly see in Android.mk files, listed
+alphabetically.</p>
+<p>But first, a note on variable naming:
+<ul>
+    <li><b>LOCAL_</b> - These variables are set per-module.  They are cleared
+    by the <code>include $(CLEAR_VARS)</code> line, so you can rely on them
+    being empty after including that file.  Most of the variables you'll use
+    in most modules are LOCAL_ variables.</li>
+    <li><b>PRIVATE_</b> - These variables are make-target-specific variables.  That
+    means they're only usable within the commands for that module.  It also
+    means that they're unlikely to change behind your back from modules that
+    are included after yours.  This 
+    <a href="http://www.gnu.org/software/make/manual/make.html#Target_002dspecific">link to the make documentation</a>
+    describes more about target-specific variables.  Please note that there
+    are a couple of these laying around the tree that aren't prefixed with
+    PRIVATE_.  It is safe, and they will be fixed as they are discovered.
+    Sorry for the confusion.</li>
+    <li><b>INTERNAL_</b> - These variables are critical to functioning of
+    the build system, so you shouldn't create variables named like this, and
+    you probably shouldn't be messing with these variables in your makefiles.
+    </li>
+    <li><b>HOST_</b> and <b>TARGET_</b> - These contain the directories
+    and definitions that are specific to either the host or the target builds.
+    Do not set variables that start with HOST_ or TARGET_ in your makefiles.
+    </li>
+    <li><b>BUILD_</b> and <b>CLEAR_VARS</b> - These contain the names of
+    well-defined template makefiles to include.  Some examples are CLEAR_VARS
+    and BUILD_HOST_PACKAGE.</li>
+    <li>Any other name is fair-game for you to use in your Android.mk.  However,
+    remember that this is a non-recursive build system, so it is possible that
+    your variable will be changed by another Android.mk included later, and be
+    different when the commands for your rule / module are executed.</li>
+</ul>
+</p>
+
+<h4>LOCAL_ASSET_FILES</h4>
+<p>In Android.mk files that <code>include $(BUILD_PACKAGE)</code> set this
+to the set of files you want built into your app.  Usually:</p>
+<p><code>LOCAL_ASSET_FILES += $(call find-subdir-assets)</code></p>
+<p>This will probably change when we switch to ant for the apps' build
+system.</p>
+
+<h4>LOCAL_CC</h4>
+<p>If you want to use a different C compiler for this module, set LOCAL_CC
+to the path to the compiler.  If LOCAL_CC is blank, the appropriate default
+compiler is used.</p>
+
+<h4>LOCAL_CXX</h4>
+<p>If you want to use a different C++ compiler for this module, set LOCAL_CXX
+to the path to the compiler.  If LOCAL_CXX is blank, the appropriate default
+compiler is used.</p>
+
+<h4>LOCAL_CFLAGS</h4>
+<p>If you have additional flags to pass into the C or C++ compiler, add
+them here.  For example:</p>
+<p><code>LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1</code></p>
+
+<h4>LOCAL_CPPFLAGS</h4>
+<p>If you have additional flags to pass into <i>only</i> the C++ compiler, add
+them here.  For example:</p>
+<p><code>LOCAL_CPPFLAGS += -ffriend-injection</code></p>
+<code>LOCAL_CPPFLAGS</code> is guaranteed to be after <code>LOCAL_CFLAGS</code>
+on the compile line, so you can use it to override flags listed in
+<code>LOCAL_CFLAGS</code>.
+
+<h4>LOCAL_CPP_EXTENSION</h4>
+<p>If your C++ files end in something other than "<code>.cpp</code>",
+you can specify the custom extension here.  For example:</p>
+<p><code>LOCAL_CPP_EXTENSION := .cc</code></p>
+Note that all C++ files for a given module must have the same
+extension; it is not currently possible to mix different extensions.
+
+<h4>LOCAL_NO_DEFAULT_COMPILER_FLAGS</h4>
+<p>Normally, the compile line for C and C++ files includes global include
+paths and global cflags.  If <code>LOCAL_NO_DEFAULT_COMPILER_FLAGS</code>
+is non-empty, none of the default includes or flags will be used when compiling
+C and C++ files in this module.
+<code>LOCAL_C_INCLUDES</code>, <code>LOCAL_CFLAGS</code>, and
+<code>LOCAL_CPPFLAGS</code> will still be used in this case, as will
+any <code>DEBUG_CFLAGS</code> that are defined for the module.
+
+<h4>LOCAL_COPY_HEADERS</h4>
+<p class=warning>This will be going away.</p>
+<p>The set of files to copy to the install include tree.  You must also
+supply <code>LOCAL_COPY_HEADERS_TO</code>.</p>
+<p>This is going away because copying headers messes up the error messages, and
+may lead to people editing those headers instead of the correct ones.  It also
+makes it easier to do bad layering in the system, which we want to avoid.  We
+also aren't doing a C/C++ SDK, so there is no ultimate requirement to copy any
+headers.</p>
+
+<h4>LOCAL_COPY_HEADERS_TO</h4>
+<p class=warning>This will be going away.</p>
+<p>The directory within "include" to copy the headers listed in
+<code>LOCAL_COPY_HEADERS</code> to.</p>
+<p>This is going away because copying headers messes up the error messages, and
+may lead to people editing those headers instead of the correct ones.  It also
+makes it easier to do bad layering in the system, which we want to avoid.  We
+also aren't doing a C/C++ SDK, so there is no ultimate requirement to copy any
+headers.</p>
+
+<h4>LOCAL_C_INCLUDES</h4>
+<p>Additional directories to instruct the C/C++ compilers to look for header
+files in.  These paths are rooted at the top of the tree.  Use
+<code>LOCAL_PATH</code> if you have subdirectories of your own that you
+want in the include paths.  For example:</p>
+<p><code>
+LOCAL_C_INCLUDES += extlibs/zlib-1.2.3<br/>
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
+</code></p>
+<p>You should not add subdirectories of include to
+<code>LOCAL_C_INCLUDES</code>, instead you should reference those files
+in the <code>#include</code> statement with their subdirectories.  For
+example:</p>
+<p><code>#include &lt;utils/KeyedVector.h&gt;</code><br/>
+not <code><s>#include &lt;KeyedVector.h&gt;</s></code></p>
+<p>There are some components that are doing this wrong, and should be cleaned
+up.</p>
+
+<h4>LOCAL_MODULE_TAGS</h4>
+<p>Set <code>LOCAL_MODULE_TAGS</code> to any number of whitespace-separated
+tags.  If the tag list is empty or contains <code>droid</code>, the module
+will get installed as part of a <code>make droid</code>.  Modules with the tag
+<code>shell_</code>$(TARGET_SHELL) will also be installed. Otherwise, it will
+only get installed by running <code>make &lt;your-module&gt;</code>
+or with the <code>make all</code> pseudotarget.</p>
+
+<h4>LOCAL_REQUIRED_MODULES</h4>
+<p>Set <code>LOCAL_REQUIRED_MODULES</code> to any number of whitespace-separated
+module names, like "libblah" or "Email".  If this module is installed, all
+of the modules that it requires will be installed as well.  This can be
+used to, e.g., ensure that necessary shared libraries or providers are
+installed when a given app is installed.
+
+<h4>LOCAL_FORCE_STATIC_EXECUTABLE</h4>
+<p>If your executable should be linked statically, set 
+<code>LOCAL_FORCE_STATIC_EXECUTABLE:=true</code>.  There is a very short
+list of libraries that we have in static form (currently only libc).  This is
+really only used for executables in /sbin on the root filesystem.</p>
+
+<h4>LOCAL_GENERATED_SOURCES</h4>
+<p>Files that you add to <code>LOCAL_GENERATED_SOURCES</code> will be
+automatically generated and then linked in when your module is built.
+See the <a href="#custom-tools">Custom Tools</a> template makefile for an
+example.</p>
+
+<h4>LOCAL_JAVACFLAGS</h4>
+<p>If you have additional flags to pass into the javac compiler, add
+them here.  For example:</p>
+<p><code>LOCAL_JAVACFLAGS += -Xlint:deprecation</code></p>
+
+<h4>LOCAL_JAVA_LIBRARIES</h4>
+<p>When linking Java apps and libraries, <code>LOCAL_JAVA_LIBRARIES</code>
+specifies which sets of java classes to include.  Currently there are
+two of these: <code>core</code> and <code>framework</code>.
+In most cases, it will look like this:</p>
+<p><code>LOCAL_JAVA_LIBRARIES := core framework</code></p>
+<p>Note that setting <code>LOCAL_JAVA_LIBRARIES</code> is not necessary
+(and is not allowed) when building an APK with
+"<code>include $(BUILD_PACKAGE)</code>".  The appropriate libraries
+will be included automatically.</p>
+
+<h4>LOCAL_LDFLAGS</h4>
+<p>You can pass additional flags to the linker by setting
+<code>LOCAL_LDFLAGS</code>.  Keep in mind that the order of parameters is
+very important to ld, so test whatever you do on all platforms.</p>
+
+<h4>LOCAL_LDLIBS</h4>
+<p><code>LOCAL_LDLIBS</code> allows you to specify additional libraries
+that are not part of the build for your executable or library.  Specify
+the libraries you want in -lxxx format; they're passed directly to the 
+link line.  However, keep in mind that there will be no dependency generated
+for these libraries.  It's most useful in simulator builds where you want
+to use a library preinstalled on the host.  The linker (ld) is a particularly
+fussy beast, so it's sometimes necessary to pass other flags here if you're
+doing something sneaky. Some examples:</p>
+<p><code>LOCAL_LDLIBS += -lcurses -lpthread<br/>
+LOCAL_LDLIBS += -Wl,-z,origin
+</code></p>
+
+<h4>LOCAL_NO_MANIFEST</h4>
+<p>If your package doesn't have a manifest (AndroidManifest.xml), then
+set <code>LOCAL_NO_MANIFEST:=true</code>.  The common resources package
+does this.</p>
+
+<h4>LOCAL_PACKAGE_NAME</h4>
+<p><code>LOCAL_PACKAGE_NAME</code> is the name of an app.  For example,
+Dialer, Contacts, etc.  This will probably change or go away when we switch
+to an ant-based build system for the apps.</p>
+
+<h4>LOCAL_PATH</h4>
+<p>The directory your Android.mk file is in. You can set it by putting the
+following as the first line in your Android.mk:</p>
+<p><code>LOCAL_PATH := $(my-dir)</code></p>
+<p>The <code>my-dir</code> macro uses the 
+<code><a href="http://www.gnu.org/software/make/manual/make.html#MAKEFILE_005fLIST-Variable">MAKEFILE_LIST</a></code>
+variable, so you must call it before you include any other makefiles.  Also,
+consider that any subdirectories you inlcude might reset LOCAL_PATH, so do your
+own stuff before you include them.  This also means that if you try to write
+several <code>include</code> lines that reference <code>LOCAL_PATH</code>,
+it won't work, because those included makefiles might reset LOCAL_PATH.
+
+<h4>LOCAL_POST_PROCESS_COMMAND</h4>
+<p>For host executables, you can specify a command to run on the module
+after it's been linked.  You might have to go through some contortions
+to get variables right because of early or late variable evaluation:</p>
+<p><code>module := $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)<br/>
+LOCAL_POST_PROCESS_COMMAND := /Developer/Tools/Rez -d __DARWIN__ -t APPL\<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-d __WXMAC__ -o $(module) Carbon.r
+</code></p>
+
+<h4>LOCAL_PREBUILT_EXECUTABLES</h4>
+<p>When including $(BUILD_PREBUILT) or $(BUILD_HOST_PREBUILT), set these to
+executables that you want copied.  They're located automatically into the
+right bin directory.</p>
+
+<h4>LOCAL_PREBUILT_LIBS</h4>
+<p>When including $(BUILD_PREBUILT) or $(BUILD_HOST_PREBUILT), set these to
+libraries that you want copied.  They're located automatically into the
+right lib directory.</p>
+
+<h4>LOCAL_SHARED_LIBRARIES</h4>
+<p>These are the libraries you directly link against.  You don't need to
+pass transitively included libraries.  Specify the name without the suffix:</p>
+<p><code>LOCAL_SHARED_LIBRARIES := \<br/>
+       &nbsp;&nbsp;&nbsp;&nbsp;libutils \<br/>
+       &nbsp;&nbsp;&nbsp;&nbsp;libui \<br/>
+       &nbsp;&nbsp;&nbsp;&nbsp;libaudio \<br/>
+       &nbsp;&nbsp;&nbsp;&nbsp;libexpat \<br/>
+       &nbsp;&nbsp;&nbsp;&nbsp;libsgl
+</code></p>
+
+<h4>LOCAL_SRC_FILES</h4>
+<p>The build system looks at <code>LOCAL_SRC_FILES</code> to know what source
+files to compile -- .cpp .c .y .l .java.  For lex and yacc files, it knows
+how to correctly do the intermediate .h and .c/.cpp files automatically.  If
+the files are in a subdirectory of the one containing the Android.mk, prefix
+them with the directory name:</p>
+<p><code>LOCAL_SRC_FILES := \<br/>
+       &nbsp;&nbsp;&nbsp;&nbsp;file1.cpp \<br/>
+       &nbsp;&nbsp;&nbsp;&nbsp;dir/file2.cpp
+</code></p>
+
+<h4>LOCAL_STATIC_LIBRARIES</h4>
+<p>These are the static libraries that you want to include in your module.
+Mostly, we use shared libraries, but there are a couple of places, like
+executables in sbin and host executables where we use static libraries instead.
+<p><code>LOCAL_STATIC_LIBRARIES := \<br/>
+       &nbsp;&nbsp;&nbsp;&nbsp;libutils \<br/>
+       &nbsp;&nbsp;&nbsp;&nbsp;libtinyxml
+</code></p>
+
+<h4>LOCAL_MODULE</h4>
+<p><code>LOCAL_MODULE</code> is the name of what's supposed to be generated
+from your Android.mk.  For exmample, for libkjs, the <code>LOCAL_MODULE</code>
+is "libkjs" (the build system adds the appropriate suffix -- .so .dylib .dll).
+For app modules, use <code>LOCAL_PACKAGE_NAME</code> instead of 
+<code>LOCAL_MODULE</code>.  We're planning on switching to ant for the apps,
+so this might become moot.</p>
+
+<h4>LOCAL_MODULE_PATH</h4>
+<p>Instructs the build system to put the module somewhere other than what's
+normal for its type.  If you override this, make sure you also set
+<code>LOCAL_UNSTRIPPED_PATH</code> if it's an executable or a shared library
+so the unstripped binary has somewhere to go.  An error will occur if you forget
+to.</p>
+<p>See <a href="#moving-modules">Putting modules elsewhere</a> for more.</p>
+
+<h4>LOCAL_UNSTRIPPED_PATH</h4>
+<p>Instructs the build system to put the unstripped version of the module
+somewhere other than what's normal for its type.  Usually, you override this
+because you overrode <code>LOCAL_MODULE_PATH</code> for an executable or a
+shared library.  If you overrode <code>LOCAL_MODULE_PATH</code>, but not 
+<code>LOCAL_UNSTRIPPED_PATH</code>, an error will occur.</p>
+<p>See <a href="#moving-modules">Putting modules elsewhere</a> for more.</p>
+
+<h4>LOCAL_WHOLE_STATIC_LIBRARIES</h4>
+<p>These are the static libraries that you want to include in your module without allowing
+the linker to remove dead code from them. This is mostly useful if you want to add a static library
+to a shared library and have the static library's content exposed from the shared library.
+<p><code>LOCAL_WHOLE_STATIC_LIBRARIES := \<br/>
+       &nbsp;&nbsp;&nbsp;&nbsp;libsqlite3_android<br/>
+</code></p>
+
+<h4>LOCAL_YACCFLAGS</h4>
+<p>Any flags to pass to invocations of yacc for your module.  A known limitation
+here is that the flags will be the same for all invocations of YACC for your
+module.  This can be fixed.  If you ever need it to be, just ask.</p>
+<p><code>LOCAL_YACCFLAGS := -p kjsyy</code></p>
+
+
+
+<h2>Implementation Details</h2>
+
+<p>You should never have to touch anything in the config directory unless
+you're adding a new platform, new tools, or adding new features to the
+build system.  In general, please consult with the build system owner(s)
+(<a href="mailto:android-build-team">android-build-team</a>) before you go
+mucking around in here.  That said, here are some notes on what's going on
+under the hood.</p>
+
+<h3>Environment Setup / buildspec.mk Versioning</h3>
+<p>In order to make easier for people when the build system changes, when
+it is necessary to make changes to buildspec.mk or to rerun the environment
+setup scripts, they contain a version number in the variable
+BUILD_ENV_SEQUENCE_NUMBER.  If this variable does not match what the build
+system expects, it fails printing an error message explaining what happened.
+If you make a change that requires an update, you need to update two places
+so this message will be printed.
+<ul>
+    <li>In config/envsetup.make, increment the
+        CORRECT_BUILD_ENV_SEQUENCE_NUMBER definition.</li>
+    <li>In buildspec.mk.default, update the BUILD_ENV_SEQUENCE_DUMBER
+        definition to match the one in config/envsetup.make</li>
+</ul>
+The scripts automatically get the value from the build system, so they will
+trigger the warning as well.
+</p>
+
+<h3>Additional makefile variables</h3>
+<p>You probably shouldn't use these variables.  Please consult
+<a href="mailto:android-build-team">android-build-team</a> before using them.
+These are mostly there for workarounds for other issues, or things that aren't
+completely done right.</p>
+
+<h4>LOCAL_ADDITIONAL_DEPENDENCIES</h4>
+<p>If your module needs to depend on anything else that
+isn't actually built in to it, you can add those make targets to 
+<code>LOCAL_ADDITIONAL_DEPENDENCIES</code>.  Usually this is a workaround
+for some other dependency that isn't created automatically.</p>
+
+<h4>LOCAL_BUILT_MODULE</h4>
+<p>When a module is built, the module is created in an intermediate
+directory then copied to its final location.  LOCAL_BUILT_MODULE is
+the full path to the intermediate file.  See LOCAL_INSTALLED_MODULE
+for the path to the final installed location of the module.</p>
+
+<h4>LOCAL_HOST</h4>
+<p>Set by the host_xxx.make includes to tell base_rules.make and the other
+includes that we're building for the host.  Kenneth did this as part of
+openbinder, and I would like to clean it up so the rules, includes and
+definitions aren't duplicated for host and target.</p>
+
+<h4>LOCAL_INSTALLED_MODULE</h4>
+<p>The fully qualified path name of the final location of the module.
+See LOCAL_BUILT_MODULE for the location of the intermediate file that
+the make rules should actually be constructing.</p>
+
+<h4>LOCAL_REPLACE_VARS</h4>
+<p>Used in some stuff remaining from the openbinder for building scripts
+with particular values set,</p>
+
+<h4>LOCAL_SCRIPTS</h4>
+<p>Used in some stuff remaining from the openbinder build system that we
+might find handy some day.</p>
+
+<h4>LOCAL_MODULE_CLASS</h4>
+<p>Which kind of module this is.  This variable is used to construct other
+variable names used to locate the modules.  See base_rules.make and
+envsetup.make.</p>
+
+<h4>LOCAL_MODULE_NAME</h4>
+<p>Set to the leaf name of the LOCAL_BUILT_MODULE.  I'm not sure,
+but it looks like it's just used in the WHO_AM_I variable to identify
+in the pretty printing what's being built.</p>
+
+<h4>LOCAL_MODULE_SUFFIX</h4>
+<p>The suffix that will be appended to <code>LOCAL_MODULE</code> to form
+<code>LOCAL_MODULE_NAME</code>.  For example, .so, .a, .dylib.</p>
+
+<h4>LOCAL_STRIP_MODULE</h4>
+<p>Calculated in base_rules.make to determine if this module should actually
+be stripped or not, based on whether <code>LOCAL_STRIPPABLE_MODULE</code>
+is set, and whether the combo is configured to ever strip modules.  With
+Iliyan's stripping tool, this might change.</p>
+
+<h4>LOCAL_STRIPPABLE_MODULE</h4>
+<p>Set by the include makefiles if that type of module is strippable. 
+Executables and shared libraries are.</p>
+
+<h4>LOCAL_SYSTEM_SHARED_LIBRARIES</h4>
+<p>Used while building the base libraries: libc, libm, libdl.  Usually
+it should be set to "none," as it is in $(CLEAR_VARS).  When building
+these libraries, it's set to the ones they link against.  For example,
+libc, libstdc++ and libdl don't link against anything, and libm links against
+libc.  Normally, when the value is none, these libraries are automatically
+linked in to executables and libraries, so you don't need to specify them
+manually.</p>
+
+
+</body>
+</html>
diff --git a/build/core/build_id.mk b/build/core/build_id.mk
new file mode 100644 (file)
index 0000000..e954794
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Defines branch-specific values.
+#
+
+# BUILD_ID is usually used to specify the branch name
+# (like "MAIN") or a branch name and a release candidate
+# (like "TC1-RC5").  It must be a single word, and is
+# capitalized by convention.
+#
+BUILD_ID := OPENMASTER
+
+# DISPLAY_BUILD_NUMBER should only be set for development branches,
+# If set, the BUILD_NUMBER (cl) is appended to the BUILD_ID for
+# a more descriptive BUILD_ID_DISPLAY, otherwise BUILD_ID_DISPLAY
+# is the same as BUILD_ID
+DISPLAY_BUILD_NUMBER := true
diff --git a/build/core/checktree b/build/core/checktree
new file mode 100644 (file)
index 0000000..b0b9cfa
--- /dev/null
@@ -0,0 +1,113 @@
+#!/usr/bin/python -E
+
+import sys, os, re
+
+excludes = [r'.*?/\.obj.*?',
+            r'.*?~',
+            r'.*?\/.DS_Store',
+            r'.*?\/.gdb_history',
+            r'.*?\/buildspec.mk',
+            r'.*?/\..*?\.swp',
+            r'.*?/out/.*?',
+            r'.*?/install/.*?']
+
+excludes_compiled = map(re.compile, excludes)
+
+def filter_excludes(str):
+    for e in excludes_compiled:
+        if e.match(str):
+            return False
+    return True
+
+def split_perforce_parts(s):
+    spaces = ((s.count(" ") + 1) / 3) * 2
+    pos = 0
+    while spaces > 0:
+        pos = s.find(" ", pos) + 1
+        spaces = spaces - 1
+    return s[pos:]
+
+def quotate(s):
+    return '"' + s + '"'
+
+class PerforceError(Exception):
+    def __init__(self,value):
+        self.value = value
+    def __str__(self):
+        return repr(self.value)
+    
+
+def run(command, regex, filt):
+    def matchit(s):
+        m = regex_compiled.match(s)
+        if m:
+            return m.group(1)
+        else:
+            return ""
+    def filterit(s):
+        if filt_compiled.match(s):
+            return True
+        else:
+            return False
+
+    fd = os.popen(command);
+    lines = fd.readlines()
+    status = fd.close()
+    if status:
+        raise PerforceError("error calling " + command)
+        
+    regex_compiled = re.compile(regex)
+    filt_compiled = re.compile(filt)
+
+    if len(lines) >= 1:
+        lines = filter(filterit, lines)
+        if len(lines) >= 1:
+            return map(matchit, lines)
+    return None
+
+try:
+    if len(sys.argv) == 1:
+        do_exclude = True
+    elif len(sys.argv) == 2 and sys.argv[1] == "-a":
+        do_exclude = False
+    else:
+        print "usage: checktree [-a]"
+        print "  -a  don't filter common crud in the tree"
+        sys.exit(1)
+
+    have = run("p4 have ...", r'[^#]+#[0-9]+ - (.*)', r'.*')
+
+    cwd = os.getcwd()
+    files = run("find . -not -type d", r'.(.*)', r'.*')
+    files = map(lambda s: cwd+s, files)
+
+    added_depot_path = run("p4 opened ...", r'([^#]+)#.*', r'.*?#[0-9]+ - add .*');
+    added = []
+    if added_depot_path:
+        added_depot_path = map(quotate, added_depot_path)
+
+        where = "p4 where " + " ".join(added_depot_path)
+        added = run(where, r'(.*)', r'.*')
+        added = map(split_perforce_parts, added)
+
+    extras = []
+
+    # Python 2.3 -- still default on Mac OS X -- does not have set()
+    # Make dict's here to support the "in" operations below
+    have = dict().fromkeys(have, 1)
+    added = dict().fromkeys(added, 1)
+
+    for file in files:
+        if not file in have:
+            if not file in added:
+                extras.append(file)
+
+    if do_exclude:
+        extras = filter(filter_excludes, extras)
+
+    for s in extras:
+        print s.replace(" ", "\\ ")
+
+except PerforceError, e:
+    sys.exit(2)
+
diff --git a/build/core/cleanbuild.mk b/build/core/cleanbuild.mk
new file mode 100644 (file)
index 0000000..cf25ce1
--- /dev/null
@@ -0,0 +1,218 @@
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+INTERNAL_CLEAN_STEPS :=
+
+# Builds up a list of clean steps.  Creates a unique
+# id for each step by taking makefile path, INTERNAL_CLEAN_BUILD_VERSION
+# and appending an increasing number of '@' characters.
+#
+# $(1): shell command to run
+# $(2): indicate to not use makefile path as part of step id if not empty.
+#       $(2) should only be used in build/core/cleanspec.mk: just for compatibility.
+define _add-clean-step
+  $(if $(strip $(INTERNAL_CLEAN_BUILD_VERSION)),, \
+      $(error INTERNAL_CLEAN_BUILD_VERSION not set))
+  $(eval _acs_makefile_prefix := $(lastword $(MAKEFILE_LIST)))
+  $(eval _acs_makefile_prefix := $(subst /,_,$(_acs_makefile_prefix)))
+  $(eval _acs_makefile_prefix := $(subst .,-,$(_acs_makefile_prefix)))
+  $(eval _acs_makefile_prefix := $(_acs_makefile_prefix)_acs)
+  $(if $($(_acs_makefile_prefix)),,\
+      $(eval $(_acs_makefile_prefix) := $(INTERNAL_CLEAN_BUILD_VERSION)))
+  $(eval $(_acs_makefile_prefix) := $($(_acs_makefile_prefix))@)
+  $(if $(strip $(2)),$(eval _acs_id := $($(_acs_makefile_prefix))),\
+      $(eval _acs_id := $(_acs_makefile_prefix)$($(_acs_makefile_prefix))))
+  $(eval INTERNAL_CLEAN_STEPS += $(_acs_id))
+  $(eval INTERNAL_CLEAN_STEP.$(_acs_id) := $(1))
+  $(eval _acs_id :=)
+  $(eval _acs_makefile_prefix :=)
+endef
+define add-clean-step
+$(eval # for build/core/cleanspec.mk, dont use makefile path as part of step id) \
+$(if $(filter %/cleanspec.mk,$(lastword $(MAKEFILE_LIST))),\
+    $(eval $(call _add-clean-step,$(1),true)),\
+    $(eval $(call _add-clean-step,$(1))))
+endef
+
+# Defines INTERNAL_CLEAN_BUILD_VERSION and the individual clean steps.
+# cleanspec.mk is outside of the core directory so that more people
+# can have permission to touch it.
+include $(BUILD_SYSTEM)/cleanspec.mk
+INTERNAL_CLEAN_BUILD_VERSION := $(strip $(INTERNAL_CLEAN_BUILD_VERSION))
+
+# If the clean_steps.mk file is missing (usually after a clean build)
+# then we won't do anything.
+CURRENT_CLEAN_BUILD_VERSION := $(INTERNAL_CLEAN_BUILD_VERSION)
+CURRENT_CLEAN_STEPS := $(INTERNAL_CLEAN_STEPS)
+
+# Read the current state from the file, if present.
+# Will set CURRENT_CLEAN_BUILD_VERSION and CURRENT_CLEAN_STEPS.
+#
+clean_steps_file := $(PRODUCT_OUT)/clean_steps.mk
+-include $(clean_steps_file)
+
+ifneq ($(CURRENT_CLEAN_BUILD_VERSION),$(INTERNAL_CLEAN_BUILD_VERSION))
+  # The major clean version is out-of-date.  Do a full clean, and
+  # don't even bother with the clean steps.
+  $(info *** A clean build is required because of a recent change.)
+  $(shell rm -rf $(OUT_DIR))
+  $(info *** Done with the cleaning, now starting the real build.)
+else
+  # The major clean version is correct.  Find the list of clean steps
+  # that we need to execute to get up-to-date.
+  steps := \
+      $(filter-out $(CURRENT_CLEAN_STEPS),$(INTERNAL_CLEAN_STEPS))
+  $(foreach step,$(steps), \
+    $(info Clean step: $(INTERNAL_CLEAN_STEP.$(step))) \
+    $(shell $(INTERNAL_CLEAN_STEP.$(step))) \
+   )
+  steps :=
+endif
+CURRENT_CLEAN_BUILD_VERSION :=
+CURRENT_CLEAN_STEPS :=
+
+# Write the new state to the file.
+#
+$(shell \
+  mkdir -p $(dir $(clean_steps_file)) && \
+  echo "CURRENT_CLEAN_BUILD_VERSION := $(INTERNAL_CLEAN_BUILD_VERSION)" > \
+      $(clean_steps_file) ;\
+  echo "CURRENT_CLEAN_STEPS := $(INTERNAL_CLEAN_STEPS)" >> \
+      $(clean_steps_file) \
+ )
+
+clean_steps_file :=
+INTERNAL_CLEAN_STEPS :=
+INTERNAL_CLEAN_BUILD_VERSION :=
+
+
+# Since products and build variants (unfortunately) share the same
+# PRODUCT_OUT staging directory, things can get out of sync if different
+# build configurations are built in the same tree.  The following logic
+# will notice when the configuration has changed and remove the files
+# necessary to keep things consistent.
+
+previous_build_config_file := $(PRODUCT_OUT)/previous_build_config.mk
+
+# TODO: this special case for the sdk is only necessary while "sdk"
+# is a valid make target.  Eventually, it will just be a product, at
+# which point TARGET_PRODUCT will handle it and we can avoid this check
+# of MAKECMDGOALS.  The "addprefix" is just to keep things pretty.
+ifneq ($(TARGET_PRODUCT),sdk)
+  building_sdk := $(addprefix -,$(filter sdk,$(MAKECMDGOALS)))
+else
+  # Don't bother with this extra part when explicitly building the sdk product.
+  building_sdk :=
+endif
+
+# A change in the list of locales warrants an installclean, too.
+locale_list := $(subst $(space),$(comma),$(strip $(PRODUCT_LOCALES)))
+
+current_build_config := \
+    $(TARGET_PRODUCT)-$(TARGET_BUILD_VARIANT)$(building_sdk)-{$(locale_list)}
+building_sdk :=
+locale_list :=
+force_installclean := false
+
+# Read the current state from the file, if present.
+# Will set PREVIOUS_BUILD_CONFIG.
+#
+PREVIOUS_BUILD_CONFIG :=
+-include $(previous_build_config_file)
+PREVIOUS_BUILD_CONFIG := $(strip $(PREVIOUS_BUILD_CONFIG))
+ifdef PREVIOUS_BUILD_CONFIG
+  ifneq "$(current_build_config)" "$(PREVIOUS_BUILD_CONFIG)"
+    $(info *** Build configuration changed: "$(PREVIOUS_BUILD_CONFIG)" -> "$(current_build_config)")
+    ifneq ($(DISABLE_AUTO_INSTALLCLEAN),true)
+      force_installclean := true
+    else
+      $(info DISABLE_AUTO_INSTALLCLEAN is set; skipping auto-clean. Your tree may be in an inconsistent state.)
+    endif
+  endif
+endif  # else, this is the first build, so no need to clean.
+PREVIOUS_BUILD_CONFIG :=
+
+# Write the new state to the file.
+#
+$(shell \
+  mkdir -p $(dir $(previous_build_config_file)) && \
+  echo "PREVIOUS_BUILD_CONFIG := $(current_build_config)" > \
+      $(previous_build_config_file) \
+ )
+previous_build_config_file :=
+current_build_config :=
+
+#
+# installclean logic
+#
+
+# The files/dirs to delete during an installclean.  This includes the
+# non-common APPS directory, which may contain the wrong resources.
+# Use "./" in front of the paths to avoid accidentally deleting random
+# parts of the filesystem if any of the *_OUT vars resolve to blank.
+#
+# Deletes all of the files that change between different build types,
+# like "make user" vs. "make sdk".  This lets you work with different
+# build types without having to do a full clean each time.  E.g.:
+#
+#     $ make -j8 all
+#     $ make installclean
+#     $ make -j8 user
+#     $ make installclean
+#     $ make -j8 sdk
+#
+installclean_files := \
+       ./$(HOST_OUT)/obj/NOTICE_FILES \
+       ./$(HOST_OUT)/sdk \
+       ./$(PRODUCT_OUT)/*.img \
+       ./$(PRODUCT_OUT)/*.txt \
+       ./$(PRODUCT_OUT)/*.xlb \
+       ./$(PRODUCT_OUT)/*.zip \
+       ./$(PRODUCT_OUT)/data \
+       ./$(PRODUCT_OUT)/obj/APPS \
+       ./$(PRODUCT_OUT)/obj/NOTICE_FILES \
+       ./$(PRODUCT_OUT)/obj/PACKAGING \
+       ./$(PRODUCT_OUT)/recovery \
+       ./$(PRODUCT_OUT)/root \
+       ./$(PRODUCT_OUT)/system \
+       ./$(PRODUCT_OUT)/dex_bootjars \
+       ./$(PRODUCT_OUT)/obj/JAVA_LIBRARIES
+
+# The files/dirs to delete during a dataclean, which removes any files
+# in the staging and emulator data partitions.
+dataclean_files := \
+       ./$(PRODUCT_OUT)/data/* \
+       ./$(PRODUCT_OUT)/data-qemu/* \
+       ./$(PRODUCT_OUT)/userdata-qemu.img
+
+# Define the rules for commandline invocation.
+.PHONY: dataclean
+dataclean: FILES := $(dataclean_files)
+dataclean:
+       $(hide) rm -rf $(FILES)
+       @echo "Deleted emulator userdata images."
+
+.PHONY: installclean
+installclean: FILES := $(installclean_files)
+installclean: dataclean
+       $(hide) rm -rf $(FILES)
+       @echo "Deleted images and staging directories."
+
+ifeq "$(force_installclean)" "true"
+  $(info *** Forcing "make installclean"...)
+  $(shell rm -rf $(dataclean_files) $(installclean_files))
+  $(info *** Done with the cleaning, now starting the real build.)
+endif
+force_installclean :=
diff --git a/build/core/cleanspec.mk b/build/core/cleanspec.mk
new file mode 100644 (file)
index 0000000..d4a8eed
--- /dev/null
@@ -0,0 +1,69 @@
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Just bump this if you want to force a clean build.
+# **********************************************************************
+# WHEN DOING SO
+# 1. DELETE ANY "add-clean-step" ENTRIES THAT HAVE PILED UP IN THIS FILE.
+# 2. REMOVE ALL FILES NAMED CleanSpec.mk.
+# 3. BUMP THE VERSION.
+# IDEALLY, THOSE STEPS SHOULD BE DONE ATOMICALLY.
+# **********************************************************************
+#
+INTERNAL_CLEAN_BUILD_VERSION := 6
+#
+# ***********************************************************************
+# Do not touch INTERNAL_CLEAN_BUILD_VERSION if you've added a clean step!
+# ***********************************************************************
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+subdir_cleanspecs := \
+    $(shell build/tools/findleaves.py --prune=out --prune=.repo --prune=.git . CleanSpec.mk)
+include $(subdir_cleanspecs)
+subdir_cleanspecs :=
diff --git a/build/core/clear_vars.mk b/build/core/clear_vars.mk
new file mode 100644 (file)
index 0000000..9badc55
--- /dev/null
@@ -0,0 +1,110 @@
+###########################################################
+## Clear out values of all variables used by rule templates.
+###########################################################
+
+LOCAL_MODULE:=
+LOCAL_MODULE_PATH:=
+LOCAL_MODULE_STEM:=
+LOCAL_DONT_CHECK_MODULE:=
+LOCAL_CHECKED_MODULE:=
+LOCAL_BUILT_MODULE:=
+LOCAL_BUILT_MODULE_STEM:=
+OVERRIDE_BUILT_MODULE_PATH:=
+LOCAL_INSTALLED_MODULE:=
+LOCAL_UNINSTALLABLE_MODULE:=
+LOCAL_INTERMEDIATE_TARGETS:=
+LOCAL_UNSTRIPPED_PATH:=
+LOCAL_MODULE_CLASS:=
+LOCAL_MODULE_SUFFIX:=
+LOCAL_PACKAGE_NAME:=
+LOCAL_OVERRIDES_PACKAGES:=
+LOCAL_EXPORT_PACKAGE_RESOURCES:=
+LOCAL_MANIFEST_PACKAGE_NAME:=
+LOCAL_REQUIRED_MODULES:=
+LOCAL_ACP_UNAVAILABLE:=
+LOCAL_MODULE_TAGS:=
+LOCAL_SRC_FILES:=
+LOCAL_PREBUILT_OBJ_FILES:=
+LOCAL_STATIC_JAVA_LIBRARIES:=
+LOCAL_STATIC_LIBRARIES:=
+LOCAL_WHOLE_STATIC_LIBRARIES:=
+LOCAL_SHARED_LIBRARIES:=
+LOCAL_IS_HOST_MODULE:=
+LOCAL_CC:=
+LOCAL_CXX:=
+LOCAL_CPP_EXTENSION:=
+LOCAL_NO_DEFAULT_COMPILER_FLAGS:=
+LOCAL_NO_FDO_SUPPORT :=
+LOCAL_ARM_MODE:=
+LOCAL_YACCFLAGS:=
+LOCAL_ASFLAGS:=
+LOCAL_CFLAGS:=
+LOCAL_CPPFLAGS:=
+LOCAL_C_INCLUDES:=
+LOCAL_LDFLAGS:=
+LOCAL_LDLIBS:=
+LOCAL_AAPT_FLAGS:=
+LOCAL_SYSTEM_SHARED_LIBRARIES:=none
+LOCAL_PREBUILT_LIBS:=
+LOCAL_PREBUILT_EXECUTABLES:=
+LOCAL_PREBUILT_JAVA_LIBRARIES:=
+LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES:=
+LOCAL_PREBUILT_STRIP_COMMENTS:=
+LOCAL_INTERMEDIATE_SOURCES:=
+LOCAL_INTERMEDIATE_SOURCE_DIR:=
+LOCAL_JAVACFLAGS:=
+LOCAL_JAVA_LIBRARIES:=
+LOCAL_NO_STANDARD_LIBRARIES:=
+LOCAL_CLASSPATH:=
+LOCAL_DROIDDOC_USE_STANDARD_DOCLET:=
+LOCAL_DROIDDOC_SOURCE_PATH:=
+LOCAL_DROIDDOC_TEMPLATE_DIR:=
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=
+LOCAL_DROIDDOC_ASSET_DIR:=
+LOCAL_DROIDDOC_CUSTOM_ASSET_DIR:=
+LOCAL_DROIDDOC_OPTIONS:=
+LOCAL_DROIDDOC_HTML_DIR:=
+LOCAL_ASSET_FILES:=
+LOCAL_ASSET_DIR:=
+LOCAL_RESOURCE_DIR:=
+LOCAL_JAVA_RESOURCE_DIRS:=
+LOCAL_JAVA_RESOURCE_FILES:=
+LOCAL_GENERATED_SOURCES:=
+LOCAL_COPY_HEADERS_TO:=
+LOCAL_COPY_HEADERS:=
+LOCAL_FORCE_STATIC_EXECUTABLE:=
+LOCAL_ADDITIONAL_DEPENDENCIES:=
+LOCAL_PRELINK_MODULE:=
+LOCAL_COMPRESS_MODULE_SYMBOLS:=
+LOCAL_STRIP_MODULE:=
+LOCAL_POST_PROCESS_COMMAND:=true
+LOCAL_JNI_SHARED_LIBRARIES:=
+LOCAL_JAR_MANIFEST:=
+LOCAL_INSTRUMENTATION_FOR:=
+LOCAL_MANIFEST_INSTRUMENTATION_FOR:=
+LOCAL_AIDL_INCLUDES:=
+LOCAL_JARJAR_RULES:=
+LOCAL_ADDITIONAL_JAVA_DIR:=
+LOCAL_ALLOW_UNDEFINED_SYMBOLS:=
+LOCAL_DX_FLAGS:=
+LOCAL_CERTIFICATE:=
+LOCAL_SDK_VERSION:=
+LOCAL_NDK_VERSION:=
+LOCAL_NO_EMMA_INSTRUMENT:=
+LOCAL_NO_EMMA_COMPILE:=
+LOCAL_PROGUARD_ENABLED:= # '',optonly,full,custom
+LOCAL_PROGUARD_FLAGS:=
+LOCAL_PROGUARD_FLAG_FILES:=
+LOCAL_EMMA_COVERAGE_FILTER:=
+LOCAL_WARNINGS_ENABLE:=
+LOCAL_MANIFEST_FILE:=
+LOCAL_BUILD_HOST_DEX:=
+LOCAL_DEX_PREOPT:=
+LOCAL_PROTOC_OPTIMIZE_TYPE:= # lite(default),micro,full
+LOCAL_PROTOC_FLAGS:=
+
+# Trim MAKEFILE_LIST so that $(call my-dir) doesn't need to
+# iterate over thousands of entries every time.
+# Leave the current makefile to make sure we don't break anything
+# that expects to be able to find the name of the current makefile.
+MAKEFILE_LIST := $(lastword $(MAKEFILE_LIST))
diff --git a/build/core/combo/HOST_darwin-x86.mk b/build/core/combo/HOST_darwin-x86.mk
new file mode 100644 (file)
index 0000000..121f89b
--- /dev/null
@@ -0,0 +1,94 @@
+#
+# Copyright (C) 2006 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Configuration for Darwin (Mac OS X) on x86.
+# Included by combo/select.mk
+
+# We build everything in 32-bit, because some host tools are
+# 32-bit-only anyway (emulator, acc), and because it gives us
+# more consistency between the host tools and the target.
+HOST_GLOBAL_CFLAGS += -m32
+HOST_GLOBAL_LDFLAGS += -m32
+
+# Use the Mac OSX SDK 10.5 if the build host is 10.6
+build_mac_version := $(shell sw_vers -productVersion)
+ifneq ($(filter 10.6.%, $(build_mac_version)),)
+sdk_105_root := /Developer/SDKs/MacOSX10.5.sdk
+ifeq ($(wildcard $(sdk_105_root)),)
+$(warning *****************************************************)
+$(warning * You are building on Mac OSX 10.6.)
+$(warning * Can not find SDK 10.5 at $(sdk_105_root))
+$(warning *****************************************************)
+$(error Stop.)
+endif
+
+HOST_GLOBAL_CFLAGS += -isysroot $(sdk_105_root) -mmacosx-version-min=10.5
+HOST_GLOBAL_LDFLAGS += -isysroot $(sdk_105_root) -mmacosx-version-min=10.5
+endif # build_mac_version is 10.6
+
+HOST_GLOBAL_CFLAGS += -fPIC
+HOST_NO_UNDEFINED_LDFLAGS := -Wl,-undefined,error
+
+HOST_CC := $(CC)
+HOST_CXX := $(CXX)
+HOST_AR := $(AR)
+HOST_STRIP := $(STRIP)
+HOST_STRIP_COMMAND = $(HOST_STRIP) --strip-debug $< -o $@
+
+HOST_SHLIB_SUFFIX := .dylib
+HOST_JNILIB_SUFFIX := .jnilib
+
+HOST_GLOBAL_CFLAGS += \
+       -include $(call select-android-config-h,darwin-x86)
+HOST_RUN_RANLIB_AFTER_COPYING := true
+HOST_GLOBAL_ARFLAGS := cqs
+
+HOST_CUSTOM_LD_COMMAND := true
+
+define transform-host-o-to-shared-lib-inner
+    $(HOST_CXX) \
+        -dynamiclib -single_module -read_only_relocs suppress \
+        $(HOST_GLOBAL_LD_DIRS) \
+        $(HOST_GLOBAL_LDFLAGS) \
+        $(PRIVATE_ALL_OBJECTS) \
+        $(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
+        $(call normalize-target-libraries,$(PRIVATE_ALL_WHOLE_STATIC_LIBRARIES)) \
+        $(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
+        $(PRIVATE_LDLIBS) \
+        -o $@ \
+        $(PRIVATE_LDFLAGS) \
+        $(HOST_LIBGCC)
+endef
+
+define transform-host-o-to-executable-inner
+$(HOST_CXX) \
+        -o $@ \
+        -Wl,-dynamic -headerpad_max_install_names \
+        $(HOST_GLOBAL_LD_DIRS) \
+        $(HOST_GLOBAL_LDFLAGS) \
+        $(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
+        $(PRIVATE_ALL_OBJECTS) \
+        $(call normalize-target-libraries,$(PRIVATE_ALL_WHOLE_STATIC_LIBRARIES)) \
+        $(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
+        $(PRIVATE_LDFLAGS) \
+        $(PRIVATE_LDLIBS) \
+        $(HOST_LIBGCC)
+endef
+
+# $(1): The file to check
+define get-file-size
+stat -f "%z" $(1)
+endef
diff --git a/build/core/combo/HOST_linux-x86.mk b/build/core/combo/HOST_linux-x86.mk
new file mode 100644 (file)
index 0000000..c871613
--- /dev/null
@@ -0,0 +1,63 @@
+#
+# Copyright (C) 2006 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Configuration for builds hosted on linux-x86.
+# Included by combo/select.mk
+
+# $(1): The file to check
+define get-file-size
+stat --format "%s" "$(1)" | tr -d '\n'
+endef
+
+# Special case for the Linux SDK: We need to use a special cross-toolchain
+# that generates machine code that will run properly on Ubuntu 8.04 (Hardy)
+# By default, the code generated by the Lucid host toolchain will not run
+# on previous versions of the platform, due to GLibc ABI mistmatches
+# (Lucid is 2.11, Hardy is 2.7)
+#
+# Note that components that need to be built as 64-bit (e.g. clearsilver
+# which is loaded by the 64-bit JVM through JNI), will have to use
+# LOCAL_CC and LOCAL_CXX to override this.
+#
+ifeq ($(TARGET_PRODUCT),sdk)
+HOST_SDK_TOOLCHAIN_PREFIX := prebuilt/linux-x86/toolchain/i686-linux-glibc2.7-4.4.3/bin/i686-linux
+# Don't do anything if the toolchain is not there
+ifneq (,$(strip $(wildcard $(HOST_SDK_TOOLCHAIN_PREFIX)-gcc)))
+HOST_CC  := $(HOST_SDK_TOOLCHAIN_PREFIX)-gcc
+HOST_CXX := $(HOST_SDK_TOOLCHAIN_PREFIX)-g++
+HOST_AR  := $(HOST_SDK_TOOLCHAIN_PREFIX)-ar
+endif # $(HOST_SDK_TOOLCHAIN_PREFIX)-gcc exists
+endif # TARGET_PRODUCT == sdk
+
+# We build everything in 32-bit, because some host tools are
+# 32-bit-only anyway (emulator, acc), and because it gives us
+# more consistency between the host tools and the target.
+# The exception is the host side of the simulator, which
+# requires to use the default size, as wxWidgets code otherwise
+# fails to build.
+ifneq ($(TARGET_SIMULATOR),true)
+HOST_GLOBAL_CFLAGS += -m32
+HOST_GLOBAL_LDFLAGS += -m32
+endif
+
+HOST_GLOBAL_CFLAGS += -fPIC
+HOST_GLOBAL_CFLAGS += \
+       -include $(call select-android-config-h,linux-x86)
+
+# Disable new longjmp in glibc 2.11 and later. See bug 2967937.
+HOST_GLOBAL_CFLAGS += -D_FORTIFY_SOURCE=0
+
+HOST_NO_UNDEFINED_LDFLAGS := -Wl,--no-undefined
diff --git a/build/core/combo/HOST_windows-x86.mk b/build/core/combo/HOST_windows-x86.mk
new file mode 100644 (file)
index 0000000..9870998
--- /dev/null
@@ -0,0 +1,67 @@
+#
+# Copyright (C) 2006 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Configuration for Linux on x86.
+# Included by combo/select.make
+
+# right now we get these from the environment, but we should
+# pick them from the tree somewhere
+TOOLS_PREFIX := #prebuilt/windows/host/bin/
+TOOLS_EXE_SUFFIX := .exe
+
+# Settings to use MinGW has a cross-compiler under Linux
+ifneq ($(findstring Linux,$(UNAME)),)
+ifneq ($(strip $(USE_MINGW)),)
+HOST_ACP_UNAVAILABLE := true
+TOOLS_PREFIX := /usr/bin/i586-mingw32msvc-
+TOOLS_EXE_SUFFIX :=
+HOST_GLOBAL_CFLAGS += -DUSE_MINGW
+HOST_C_INCLUDES += /usr/lib/gcc/i586-mingw32msvc/3.4.4/include
+HOST_GLOBAL_LD_DIRS += -L/usr/i586-mingw32msvc/lib
+endif
+endif
+
+HOST_CC := $(TOOLS_PREFIX)gcc$(TOOLS_EXE_SUFFIX)
+HOST_CXX := $(TOOLS_PREFIX)g++$(TOOLS_EXE_SUFFIX)
+HOST_AR := $(TOOLS_PREFIX)ar$(TOOLS_EXE_SUFFIX)
+
+HOST_GLOBAL_CFLAGS += -include $(call select-android-config-h,windows)
+HOST_GLOBAL_LDFLAGS += --enable-stdcall-fixup
+
+# when building under Cygwin, ensure that we use Mingw compilation by default.
+# you can disable this (i.e. to generate Cygwin executables) by defining the
+# USE_CYGWIN variable in your environment, e.g.:
+#
+#   export USE_CYGWIN=1
+#
+# note that the -mno-cygwin flags are not needed when cross-compiling the
+# Windows host tools on Linux
+#
+ifneq ($(findstring CYGWIN,$(UNAME)),)
+ifeq ($(strip $(USE_CYGWIN)),)
+HOST_GLOBAL_CFLAGS += -mno-cygwin
+HOST_GLOBAL_LDFLAGS += -mno-cygwin -mconsole
+endif
+endif
+
+HOST_SHLIB_SUFFIX := .dll
+HOST_EXECUTABLE_SUFFIX := .exe
+
+# $(1): The file to check
+# TODO: find out what format cygwin's stat(1) uses
+define get-file-size
+999999999
+endef
diff --git a/build/core/combo/TARGET_linux-arm.mk b/build/core/combo/TARGET_linux-arm.mk
new file mode 100644 (file)
index 0000000..6139b67
--- /dev/null
@@ -0,0 +1,283 @@
+#
+# Copyright (C) 2006 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Configuration for Linux on ARM.
+# Included by combo/select.mk
+
+# You can set TARGET_ARCH_VARIANT to use an arch version other
+# than ARMv5TE. Each value should correspond to a file named
+# $(BUILD_COMBOS)/arch/<name>.mk which must contain
+# makefile variable definitions similar to the preprocessor
+# defines in system/core/include/arch/<combo>/AndroidConfig.h. Their
+# purpose is to allow module Android.mk files to selectively compile
+# different versions of code based upon the funtionality and
+# instructions available in a given architecture version.
+#
+# The blocks also define specific arch_variant_cflags, which
+# include defines, and compiler settings for the given architecture
+# version.
+#
+ifeq ($(strip $(TARGET_ARCH_VARIANT)),)
+TARGET_ARCH_VARIANT := armv5te
+endif
+
+TARGET_ARCH_SPECIFIC_MAKEFILE := $(BUILD_COMBOS)/arch/$(TARGET_ARCH)/$(TARGET_ARCH_VARIANT).mk
+ifeq ($(strip $(wildcard $(TARGET_ARCH_SPECIFIC_MAKEFILE))),)
+$(error Unknown ARM architecture version: $(TARGET_ARCH_VARIANT))
+endif
+
+include $(TARGET_ARCH_SPECIFIC_MAKEFILE)
+
+# You can set TARGET_TOOLS_PREFIX to get gcc from somewhere else
+ifeq ($(strip $(TARGET_TOOLS_PREFIX)),)
+TARGET_TOOLS_PREFIX := \
+       prebuilt/$(HOST_PREBUILT_TAG)/toolchain/arm-eabi-4.4.3/bin/arm-eabi-
+endif
+
+TARGET_CC := $(TARGET_TOOLS_PREFIX)gcc$(HOST_EXECUTABLE_SUFFIX)
+TARGET_CXX := $(TARGET_TOOLS_PREFIX)g++$(HOST_EXECUTABLE_SUFFIX)
+TARGET_AR := $(TARGET_TOOLS_PREFIX)ar$(HOST_EXECUTABLE_SUFFIX)
+TARGET_OBJCOPY := $(TARGET_TOOLS_PREFIX)objcopy$(HOST_EXECUTABLE_SUFFIX)
+TARGET_LD := $(TARGET_TOOLS_PREFIX)ld$(HOST_EXECUTABLE_SUFFIX)
+TARGET_STRIP := $(HOST_OUT_EXECUTABLES)/soslim$(HOST_EXECUTABLE_SUFFIX)
+TARGET_STRIP_COMMAND = $(TARGET_STRIP) --strip --shady --quiet $< --outfile $@
+
+TARGET_NO_UNDEFINED_LDFLAGS := -Wl,--no-undefined
+
+TARGET_arm_CFLAGS :=    -O2 \
+                        -fomit-frame-pointer \
+                        -fstrict-aliasing    \
+                        -funswitch-loops     \
+                        -finline-limit=300
+
+# Modules can choose to compile some source as thumb. As
+# non-thumb enabled targets are supported, this is treated
+# as a 'hint'. If thumb is not enabled, these files are just
+# compiled as ARM.
+ifeq ($(ARCH_ARM_HAVE_THUMB_SUPPORT),true)
+TARGET_thumb_CFLAGS :=  -mthumb \
+                        -Os \
+                        -fomit-frame-pointer \
+                        -fno-strict-aliasing \
+                        -finline-limit=64
+else
+TARGET_thumb_CFLAGS := $(TARGET_arm_CFLAGS)
+endif
+
+# Set FORCE_ARM_DEBUGGING to "true" in your buildspec.mk
+# or in your environment to force a full arm build, even for
+# files that are normally built as thumb; this can make
+# gdb debugging easier.  Don't forget to do a clean build.
+#
+# NOTE: if you try to build a -O0 build with thumb, several
+# of the libraries (libpv, libwebcore, libkjs) need to be built
+# with -mlong-calls.  When built at -O0, those libraries are
+# too big for a thumb "BL <label>" to go from one end to the other.
+ifeq ($(FORCE_ARM_DEBUGGING),true)
+  TARGET_arm_CFLAGS += -fno-omit-frame-pointer -fno-strict-aliasing
+  TARGET_thumb_CFLAGS += -marm -fno-omit-frame-pointer
+endif
+
+android_config_h := $(call select-android-config-h,linux-arm)
+arch_include_dir := $(dir $(android_config_h))
+
+TARGET_GLOBAL_CFLAGS += \
+                       -msoft-float -fpic \
+                       -ffunction-sections \
+                       -funwind-tables \
+                       -fstack-protector \
+                       -Wa,--noexecstack \
+                       -Werror=format-security \
+                       -fno-short-enums \
+                       $(arch_variant_cflags) \
+                       -include $(android_config_h) \
+                       -I $(arch_include_dir)
+
+# This is to avoid the dreaded warning compiler message:
+#   note: the mangling of 'va_list' has changed in GCC 4.4
+#
+# The fact that the mangling changed does not affect the NDK ABI
+# very fortunately (since none of the exposed APIs used va_list
+# in their exported C++ functions). Also, GCC 4.5 has already
+# removed the warning from the compiler.
+#
+TARGET_GLOBAL_CFLAGS += -Wno-psabi
+
+TARGET_GLOBAL_LDFLAGS += \
+                       -Wl,-z,noexecstack \
+                       $(arch_variant_ldflags)
+
+# We only need thumb interworking in cases where thumb support
+# is available in the architecture, and just to be sure, (and
+# since sometimes thumb-interwork appears to be default), we
+# specifically disable when thumb support is unavailable.
+ifeq ($(ARCH_ARM_HAVE_THUMB_SUPPORT),true)
+TARGET_GLOBAL_CFLAGS +=        -mthumb-interwork
+else
+TARGET_GLOBAL_CFLAGS +=        -mno-thumb-interwork
+endif
+
+TARGET_GLOBAL_CPPFLAGS += -fvisibility-inlines-hidden
+
+TARGET_RELEASE_CFLAGS := \
+                       -DNDEBUG \
+                       -g \
+                       -Wstrict-aliasing=2 \
+                       -finline-functions \
+                       -fno-inline-functions-called-once \
+                       -fgcse-after-reload \
+                       -frerun-cse-after-loop \
+                       -frename-registers
+
+libc_root := bionic/libc
+libm_root := bionic/libm
+libstdc++_root := bionic/libstdc++
+libthread_db_root := bionic/libthread_db
+
+
+## on some hosts, the target cross-compiler is not available so do not run this command
+ifneq ($(wildcard $(TARGET_CC)),)
+# We compile with the global cflags to ensure that
+# any flags which affect libgcc are correctly taken
+# into account.
+TARGET_LIBGCC := $(shell $(TARGET_CC) $(TARGET_GLOBAL_CFLAGS) -print-libgcc-file-name)
+endif
+
+# Define FDO (Feedback Directed Optimization) options.
+
+TARGET_FDO_CFLAGS:=
+TARGET_FDO_LIB:=
+
+target_libgcov := $(shell $(TARGET_CC) $(TARGET_GLOBAL_CFLAGS) \
+        --print-file-name=libgcov.a)
+ifneq ($(strip $(BUILD_FDO_INSTRUMENT)),)
+  # Set BUILD_FDO_INSTRUMENT=true to turn on FDO instrumentation.
+  # The profile will be generated on /data/local/tmp/profile on the device.
+  TARGET_FDO_CFLAGS := -fprofile-generate=/data/local/tmp/profile -DANDROID_FDO
+  TARGET_FDO_LIB := $(target_libgcov)
+else
+  # If BUILD_FDO_INSTRUMENT is turned off, then consider doing the FDO optimizations.
+  # Set TARGET_FDO_PROFILE_PATH to set a custom profile directory for your build.
+  ifeq ($(strip $(TARGET_FDO_PROFILE_PATH)),)
+    TARGET_FDO_PROFILE_PATH := fdo/profiles/$(TARGET_ARCH)/$(TARGET_ARCH_VARIANT)
+  else
+    ifeq ($(strip $(wildcard $(TARGET_FDO_PROFILE_PATH))),)
+      $(warning Custom TARGET_FDO_PROFILE_PATH supplied, but directory does not exist. Turn off FDO.)
+    endif
+  endif
+
+  # If the FDO profile directory can't be found, then FDO is off.
+  ifneq ($(strip $(wildcard $(TARGET_FDO_PROFILE_PATH))),)
+    TARGET_FDO_CFLAGS := -fprofile-use=$(TARGET_FDO_PROFILE_PATH) -DANDROID_FDO
+    TARGET_FDO_LIB := $(target_libgcov)
+  endif
+endif
+
+
+# unless CUSTOM_KERNEL_HEADERS is defined, we're going to use
+# symlinks located in out/ to point to the appropriate kernel
+# headers. see 'config/kernel_headers.make' for more details
+#
+ifneq ($(CUSTOM_KERNEL_HEADERS),)
+    KERNEL_HEADERS_COMMON := $(CUSTOM_KERNEL_HEADERS)
+    KERNEL_HEADERS_ARCH   := $(CUSTOM_KERNEL_HEADERS)
+else
+    KERNEL_HEADERS_COMMON := $(libc_root)/kernel/common
+    KERNEL_HEADERS_ARCH   := $(libc_root)/kernel/arch-$(TARGET_ARCH)
+endif
+KERNEL_HEADERS := $(KERNEL_HEADERS_COMMON) $(KERNEL_HEADERS_ARCH)
+
+TARGET_C_INCLUDES := \
+       $(libc_root)/arch-arm/include \
+       $(libc_root)/include \
+       $(libstdc++_root)/include \
+       $(KERNEL_HEADERS) \
+       $(libm_root)/include \
+       $(libm_root)/include/arch/arm \
+       $(libthread_db_root)/include
+
+TARGET_CRTBEGIN_STATIC_O := $(TARGET_OUT_STATIC_LIBRARIES)/crtbegin_static.o
+TARGET_CRTBEGIN_DYNAMIC_O := $(TARGET_OUT_STATIC_LIBRARIES)/crtbegin_dynamic.o
+TARGET_CRTEND_O := $(TARGET_OUT_STATIC_LIBRARIES)/crtend_android.o
+
+TARGET_CRTBEGIN_SO_O := $(TARGET_OUT_STATIC_LIBRARIES)/crtbegin_so.o
+TARGET_CRTEND_SO_O := $(TARGET_OUT_STATIC_LIBRARIES)/crtend_so.o
+
+TARGET_STRIP_MODULE:=true
+
+TARGET_DEFAULT_SYSTEM_SHARED_LIBRARIES := libc libstdc++ libm
+
+TARGET_CUSTOM_LD_COMMAND := true
+
+# Enable the Dalvik JIT compiler if not already specified.
+ifeq ($(strip $(WITH_JIT)),)
+    WITH_JIT := true
+endif
+
+define transform-o-to-shared-lib-inner
+$(TARGET_CXX) \
+       -nostdlib -Wl,-soname,$(notdir $@) -Wl,-T,$(BUILD_SYSTEM)/armelf.xsc \
+       -Wl,--gc-sections \
+       -Wl,-shared,-Bsymbolic \
+       $(PRIVATE_TARGET_GLOBAL_LD_DIRS) \
+       $(PRIVATE_ALL_OBJECTS) \
+       $(PRIVATE_TARGET_CRTBEGIN_SO_O) \
+       -Wl,--whole-archive \
+       $(call normalize-host-libraries,$(PRIVATE_ALL_WHOLE_STATIC_LIBRARIES)) \
+       -Wl,--no-whole-archive \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
+       -o $@ \
+       $(PRIVATE_TARGET_GLOBAL_LDFLAGS) \
+       $(PRIVATE_LDFLAGS) \
+       $(PRIVATE_TARGET_FDO_LIB) \
+       $(PRIVATE_TARGET_LIBGCC) \
+       $(PRIVATE_TARGET_CRTEND_SO_O)
+endef
+
+define transform-o-to-executable-inner
+$(TARGET_CXX) -nostdlib -Bdynamic -Wl,-T,$(BUILD_SYSTEM)/armelf.x \
+       -Wl,-dynamic-linker,/system/bin/linker \
+    -Wl,--gc-sections \
+       -Wl,-z,nocopyreloc \
+       -o $@ \
+       $(TARGET_GLOBAL_LD_DIRS) \
+       -Wl,-rpath-link=$(TARGET_OUT_INTERMEDIATE_LIBRARIES) \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
+       $(TARGET_CRTBEGIN_DYNAMIC_O) \
+       $(PRIVATE_ALL_OBJECTS) \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
+       $(TARGET_GLOBAL_LDFLAGS) \
+       $(PRIVATE_LDFLAGS) \
+       $(TARGET_FDO_LIB) \
+       $(TARGET_LIBGCC) \
+       $(TARGET_CRTEND_O)
+endef
+
+define transform-o-to-static-executable-inner
+$(TARGET_CXX) -nostdlib -Bstatic -Wl,-T,$(BUILD_SYSTEM)/armelf.x \
+    -Wl,--gc-sections \
+       -o $@ \
+       $(TARGET_GLOBAL_LD_DIRS) \
+       $(TARGET_CRTBEGIN_STATIC_O) \
+       $(TARGET_GLOBAL_LDFLAGS) \
+       $(PRIVATE_LDFLAGS) \
+       $(PRIVATE_ALL_OBJECTS) \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
+       $(TARGET_FDO_LIB) \
+       $(TARGET_LIBGCC) \
+       $(TARGET_CRTEND_O)
+endef
diff --git a/build/core/combo/TARGET_linux-sh.mk b/build/core/combo/TARGET_linux-sh.mk
new file mode 100644 (file)
index 0000000..cf945fe
--- /dev/null
@@ -0,0 +1,166 @@
+#
+# Copyright (C) 2006 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Configuration for Linux on SuperH.
+# Included by combo/select.make
+
+# You can set TARGET_TOOLS_PREFIX to get gcc from somewhere else
+ifeq ($(strip $(TARGET_TOOLS_PREFIX)),)
+TARGET_TOOLS_PREFIX := \
+       prebuilt/$(HOST_PREBUILT_TAG)/toolchain/sh-4.3.3/bin/sh-linux-gnu-
+endif
+
+TARGET_CC := $(TARGET_TOOLS_PREFIX)gcc$(HOST_EXECUTABLE_SUFFIX)
+TARGET_CXX := $(TARGET_TOOLS_PREFIX)c++$(HOST_EXECUTABLE_SUFFIX)
+TARGET_AR := $(TARGET_TOOLS_PREFIX)ar$(HOST_EXECUTABLE_SUFFIX)
+TARGET_OBJCOPY := $(TARGET_TOOLS_PREFIX)objcopy$(HOST_EXECUTABLE_SUFFIX)
+TARGET_LD := $(TARGET_TOOLS_PREFIX)ld$(HOST_EXECUTABLE_SUFFIX)
+TARGET_STRIP := $(TARGET_TOOLS_PREFIX)strip$(HOST_EXECUTABLE_SUFFIX)
+TARGET_STRIP_COMMAND = $(TARGET_STRIP) --strip-debug $< -o $@
+
+TARGET_NO_UNDEFINED_LDFLAGS := -Wl,--no-undefined
+
+TARGET_sh_release_CFLAGS :=     -O2 \
+                                -fomit-frame-pointer \
+                                -fstrict-aliasing    \
+                                -funswitch-loops     \
+                                -finline-limit=300
+
+# When building for debug, compile everything as superh.
+TARGET_sh_debug_CFLAGS := $(TARGET_sh_release_CFLAGS) -fno-omit-frame-pointer -fno-strict-aliasing
+
+TARGET_GLOBAL_CFLAGS += \
+                       -fpic \
+                       -ffunction-sections \
+                       -funwind-tables \
+                       -fstack-protector \
+                       -include $(call select-android-config-h,linux-sh)
+
+TARGET_GLOBAL_CPPFLAGS += \
+                       -fno-use-cxa-atexit \
+                       -fvisibility-inlines-hidden
+
+TARGET_RELEASE_CFLAGS := \
+                       -DSK_RELEASE -DNDEBUG \
+                       -O2 -g \
+                       -Wstrict-aliasing=2 \
+                       -finline-functions \
+                       -fno-inline-functions-called-once \
+                       -fgcse-after-reload \
+                       -frerun-cse-after-loop \
+                       -frename-registers \
+                       -fno-builtin
+
+libc_root := bionic/libc
+libm_root := bionic/libm
+libstdc++_root := bionic/libstdc++
+libthread_db_root := bionic/libthread_db
+
+
+## on some hosts, the target cross-compiler is not available so do not run this command
+ifneq ($(wildcard $(TARGET_CC)),)
+# We compile with the global cflags to ensure that
+# any flags which affect libgcc are correctly taken
+# into account.
+LIBGCC_FILENAME := $(shell $(TARGET_CC) $(TARGET_GLOBAL_CFLAGS) -print-libgcc-file-name)
+LIBGCC_EH_FILENAME := $(subst libgcc,libgcc_eh,$(LIBGCC_FILENAME))
+TARGET_LIBGCC := $(LIBGCC_EH_FILENAME) $(LIBGCC_FILENAME)
+endif
+
+# unless CUSTOM_KERNEL_HEADERS is defined, we're going to use
+# symlinks located in out/ to point to the appropriate kernel
+# headers. see 'config/kernel_headers.make' for more details
+#
+ifneq ($(CUSTOM_KERNEL_HEADERS),)
+    KERNEL_HEADERS_COMMON := $(CUSTOM_KERNEL_HEADERS)
+    KERNEL_HEADERS_ARCH   := $(CUSTOM_KERNEL_HEADERS)
+else
+    KERNEL_HEADERS_COMMON := $(libc_root)/kernel/common
+    KERNEL_HEADERS_ARCH   := $(libc_root)/kernel/arch-$(TARGET_ARCH)
+endif
+KERNEL_HEADERS := $(KERNEL_HEADERS_COMMON) $(KERNEL_HEADERS_ARCH)
+
+TARGET_C_INCLUDES := \
+       $(libc_root)/arch-sh/include \
+       $(libc_root)/include \
+       $(libstdc++_root)/include \
+       $(KERNEL_HEADERS) \
+       $(libm_root)/include \
+       $(libm_root)/include/arch/sh \
+       $(libthread_db_root)/include
+
+TARGET_CRTBEGIN_STATIC_O := $(TARGET_OUT_STATIC_LIBRARIES)/crtbegin_static.o
+TARGET_CRTBEGIN_DYNAMIC_O := $(TARGET_OUT_STATIC_LIBRARIES)/crtbegin_dynamic.o
+TARGET_CRTEND_O := $(TARGET_OUT_STATIC_LIBRARIES)/crtend_android.o
+TARGET_CRTBEGIN_SO_O := $(TARGET_OUT_STATIC_LIBRARIES)/sobegin.o
+TARGET_CRTEND_SO_O := $(TARGET_OUT_STATIC_LIBRARIES)/soend.o
+
+TARGET_STRIP_MODULE:=true
+
+TARGET_DEFAULT_SYSTEM_SHARED_LIBRARIES := libc libstdc++ libm
+
+TARGET_CUSTOM_LD_COMMAND := true
+define transform-o-to-shared-lib-inner
+$(TARGET_CXX) \
+       -nostdlib -Wl,-soname,$(notdir $@) -Wl,-T,$(BUILD_SYSTEM)/shlelf.xsc \
+       -Wl,--gc-sections -Wl,-z,norelro \
+       -Wl,-shared,-Bsymbolic \
+       $(PRIVATE_TARGET_GLOBAL_LD_DIRS) \
+       $(PRIVATE_TARGET_CRTBEGIN_SO_O) \
+       $(PRIVATE_ALL_OBJECTS) \
+       -Wl,--whole-archive \
+       $(call normalize-host-libraries,$(PRIVATE_ALL_WHOLE_STATIC_LIBRARIES)) \
+       -Wl,--no-whole-archive \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
+       -o $@ \
+       $(PRIVATE_LDFLAGS) \
+       $(subst -lrt,, $(subst -lpthread,,$(PRIVATE_LDLIBS))) \
+       $(PRIVATE_TARGET_LIBGCC) \
+       $(PRIVATE_TARGET_CRTEND_SO_O)
+endef
+
+define transform-o-to-executable-inner
+$(TARGET_CXX) -nostdlib -Bdynamic  -Wl,-T,$(BUILD_SYSTEM)/shlelf.x \
+       -Wl,-dynamic-linker,/system/bin/linker \
+       -Wl,--gc-sections -Wl,-z,norelro \
+       -Wl,-z,nocopyreloc \
+       -o $@ \
+       $(TARGET_GLOBAL_LD_DIRS) \
+       -Wl,-rpath-link=$(TARGET_OUT_INTERMEDIATE_LIBRARIES) \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
+       $(TARGET_CRTBEGIN_DYNAMIC_O) \
+       $(PRIVATE_ALL_OBJECTS) \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
+       $(PRIVATE_LDFLAGS) \
+       $(TARGET_LIBGCC) \
+       $(subst -lrt,, $(subst -lpthread,,$(PRIVATE_LDLIBS))) \
+       $(TARGET_CRTEND_O)
+endef
+
+define transform-o-to-static-executable-inner
+$(TARGET_CXX) -nostdlib -Bstatic  -Wl,-T,$(BUILD_SYSTEM)/shlelf.x \
+       -Wl,--gc-sections -Wl,-z,norelro \
+       -o $@ \
+       $(TARGET_GLOBAL_LD_DIRS) \
+       $(TARGET_CRTBEGIN_STATIC_O) \
+       $(PRIVATE_LDFLAGS) \
+       $(PRIVATE_ALL_OBJECTS) \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
+       $(TARGET_LIBGCC) \
+       $(subst -lrt,, $(subst -lpthread,,$(PRIVATE_LDLIBS))) \
+       $(TARGET_CRTEND_O)
+endef
diff --git a/build/core/combo/TARGET_linux-x86.mk b/build/core/combo/TARGET_linux-x86.mk
new file mode 100644 (file)
index 0000000..86695a4
--- /dev/null
@@ -0,0 +1,174 @@
+#
+# Copyright (C) 2006 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Configuration for Linux on x86 as a target.
+# Included by combo/select.mk
+
+ifeq ($(TARGET_SIMULATOR),true)
+# When building for the simulator, use the HOST settings as TARGET settings
+TARGET_CC := $(HOST_CC)
+TARGET_CXX := $(HOST_CXX)
+TARGET_AR := $(HOST_AR)
+TARGET_GLOBAL_CFLAGS := $(HOST_GLOBAL_CFLAGS) -m32
+TARGET_GLOBAL_LDFLAGS := $(HOST_GLOBAL_LDFLAGS) -m32 -lpthread
+TARGET_NO_UNDEFINED_LDFLAGS := $(HOST_NO_UNDEFINED_LDFLAGS)
+ifeq ($(strip $(TARGET_ARCH_VARIANT)),)
+TARGET_ARCH_VARIANT := x86
+endif
+else #simulator
+
+# Provide a default variant.
+ifeq ($(strip $(TARGET_ARCH_VARIANT)),)
+TARGET_ARCH_VARIANT := x86
+endif
+
+# You can set TARGET_TOOLS_PREFIX to get gcc from somewhere else
+ifeq ($(strip $(TARGET_TOOLS_PREFIX)),)
+TARGET_TOOLS_PREFIX := \
+       prebuilt/$(HOST_PREBUILT_TAG)/toolchain/i686-unknown-linux-gnu-4.2.1/bin/i686-unknown-linux-gnu-
+endif
+
+TARGET_CC := $(TARGET_TOOLS_PREFIX)gcc$(HOST_EXECUTABLE_SUFFIX)
+TARGET_CXX := $(TARGET_TOOLS_PREFIX)g++$(HOST_EXECUTABLE_SUFFIX)
+TARGET_AR := $(TARGET_TOOLS_PREFIX)ar$(HOST_EXECUTABLE_SUFFIX)
+TARGET_OBJCOPY := $(TARGET_TOOLS_PREFIX)objcopy$(HOST_EXECUTABLE_SUFFIX)
+TARGET_LD := $(TARGET_TOOLS_PREFIX)ld$(HOST_EXECUTABLE_SUFFIX)
+TARGET_STRIP := $(TARGET_TOOLS_PREFIX)strip$(HOST_EXECUTABLE_SUFFIX)
+TARGET_STRIP_COMMAND = $(TARGET_STRIP) --strip-debug $< -o $@
+
+ifneq ($(wildcard $(TARGET_CC)),)
+TARGET_LIBGCC := \
+       $(shell $(TARGET_CC) -m32 -print-file-name=libgcc.a) \
+        $(shell $(TARGET_CC) -m32 -print-file-name=libgcc_eh.a)
+endif
+
+TARGET_NO_UNDEFINED_LDFLAGS := -Wl,--no-undefined
+
+libc_root := bionic/libc
+libm_root := bionic/libm
+libstdc++_root := bionic/libstdc++
+libthread_db_root := bionic/libthread_db
+
+# unless CUSTOM_KERNEL_HEADERS is defined, we're going to use
+# symlinks located in out/ to point to the appropriate kernel
+# headers. see 'config/kernel_headers.make' for more details
+#
+ifneq ($(CUSTOM_KERNEL_HEADERS),)
+    KERNEL_HEADERS_COMMON := $(CUSTOM_KERNEL_HEADERS)
+    KERNEL_HEADERS_ARCH   := $(CUSTOM_KERNEL_HEADERS)
+else
+    KERNEL_HEADERS_COMMON := $(libc_root)/kernel/common
+    KERNEL_HEADERS_ARCH   := $(libc_root)/kernel/arch-$(TARGET_ARCH)
+endif
+KERNEL_HEADERS := $(KERNEL_HEADERS_COMMON) $(KERNEL_HEADERS_ARCH)
+
+TARGET_GLOBAL_CFLAGS += \
+                       -Ulinux \
+                       -m32 \
+                       -fPIC \
+                       -include $(call select-android-config-h,target_linux-x86)
+
+TARGET_GLOBAL_CPPFLAGS += \
+                       -fno-use-cxa-atexit
+
+ifeq ($(TARGET_ARCH_VARIANT),x86-atom)
+    TARGET_GLOBAL_CFLAGS += -mtune=i686 -DUSE_SSSE3 -DUSE_SSE2 -mfpmath=sse -msse2
+else
+    TARGET_GLOBAL_CFLAGS += -march=i686
+endif
+
+TARGET_GLOBAL_CFLAGS += -D__ANDROID__
+TARGET_GLOBAL_LDFLAGS += -m32
+
+
+TARGET_C_INCLUDES := \
+       $(libc_root)/arch-x86/include \
+       $(libc_root)/include \
+       $(libstdc++_root)/include \
+       $(KERNEL_HEADERS) \
+       $(libm_root)/include \
+       $(libm_root)/include/i387 \
+       $(libthread_db_root)/include
+
+TARGET_CRTBEGIN_STATIC_O := $(TARGET_OUT_STATIC_LIBRARIES)/crtbegin_static.o
+TARGET_CRTBEGIN_DYNAMIC_O := $(TARGET_OUT_STATIC_LIBRARIES)/crtbegin_dynamic.o
+TARGET_CRTEND_O := $(TARGET_OUT_STATIC_LIBRARIES)/crtend_android.o
+
+
+TARGET_CRTBEGIN_SO_O := $(TARGET_OUT_STATIC_LIBRARIES)/crtbegin_so.o
+TARGET_CRTEND_SO_O := $(TARGET_OUT_STATIC_LIBRARIES)/crtend_so.o
+
+TARGET_STRIP_MODULE:=true
+
+TARGET_DEFAULT_SYSTEM_SHARED_LIBRARIES := libc libstdc++ libm
+
+TARGET_CUSTOM_LD_COMMAND := true
+define transform-o-to-shared-lib-inner
+$(TARGET_CXX) \
+       $(PRIVATE_TARGET_GLOBAL_LDFLAGS) \
+        -nostdlib -Wl,-soname,$(notdir $@) \
+        -shared -Bsymbolic \
+       $(TARGET_GLOBAL_CFLAGS) \
+       $(PRIVATE_TARGET_GLOBAL_LD_DIRS) \
+       $(PRIVATE_TARGET_CRTBEGIN_SO_O) \
+       $(PRIVATE_ALL_OBJECTS) \
+       -Wl,--whole-archive \
+       $(call normalize-host-libraries,$(PRIVATE_ALL_WHOLE_STATIC_LIBRARIES)) \
+       -Wl,--no-whole-archive \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
+       -o $@ \
+       $(PRIVATE_LDFLAGS) \
+       $(PRIVATE_TARGET_LIBGCC) \
+       $(PRIVATE_TARGET_CRTEND_SO_O)
+endef
+
+
+define transform-o-to-executable-inner
+$(TARGET_CXX) \
+       $(TARGET_GLOBAL_LDFLAGS) \
+       -nostdlib -Bdynamic \
+       -Wl,-dynamic-linker,/system/bin/linker \
+       -Wl,-z,nocopyreloc \
+       -o $@ \
+       $(TARGET_GLOBAL_LD_DIRS) \
+       -Wl,-rpath-link=$(TARGET_OUT_INTERMEDIATE_LIBRARIES) \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
+       $(TARGET_CRTBEGIN_DYNAMIC_O) \
+       $(PRIVATE_ALL_OBJECTS) \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
+       $(PRIVATE_LDFLAGS) \
+       $(TARGET_LIBGCC) \
+       $(TARGET_CRTEND_O)
+endef
+
+define transform-o-to-static-executable-inner
+$(TARGET_CXX) \
+       $(TARGET_GLOBAL_LDFLAGS) \
+       -nostdlib -Bstatic \
+       -o $@ \
+       $(TARGET_GLOBAL_LD_DIRS) \
+       $(TARGET_CRTBEGIN_STATIC_O) \
+       $(PRIVATE_LDFLAGS) \
+       $(PRIVATE_ALL_OBJECTS) \
+       -Wl,--start-group \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
+       $(TARGET_LIBGCC) \
+       -Wl,--end-group \
+       $(TARGET_CRTEND_O)
+endef
+
+endif #simulator
diff --git a/build/core/combo/arch/arm/armv4t.mk b/build/core/combo/arch/arm/armv4t.mk
new file mode 100644 (file)
index 0000000..abc8fa2
--- /dev/null
@@ -0,0 +1,23 @@
+# Configuration for Linux on ARM.
+# Generating binaries for the ARMv4T architecture and higher
+#
+# Supporting armv4 (without thumb) does not make much sense since
+# it's mostly an obsoleted instruction set architecture (only available
+# in StrongArm and arm8). Supporting armv4 will require a lot of conditional
+# code in assembler source since the bx (branch and exchange) instruction is
+# not supported.
+#
+$(warning ARMv4t support is currently a work in progress. It does not work right now!)
+ARCH_ARM_HAVE_THUMB_SUPPORT := false
+ARCH_ARM_HAVE_THUMB_INTERWORKING := false
+ARCH_ARM_HAVE_64BIT_DATA := false
+ARCH_ARM_HAVE_HALFWORD_MULTIPLY := false
+ARCH_ARM_HAVE_CLZ := false
+ARCH_ARM_HAVE_FFS := false
+
+DEFAULT_TARGET_CPU := arm920t
+
+# Note: Hard coding the 'tune' value here is probably not ideal,
+# and a better solution should be found in the future.
+#
+arch_variant_cflags := -march=armv4t -mtune=arm920t -D__ARM_ARCH_4T__
diff --git a/build/core/combo/arch/arm/armv5te-vfp.mk b/build/core/combo/arch/arm/armv5te-vfp.mk
new file mode 100644 (file)
index 0000000..75299ac
--- /dev/null
@@ -0,0 +1,7 @@
+# At the moment, use the same settings than the one
+# for armv5te, since TARGET_ARCH_VARIANT := armv5te-vfp
+# will only be used to select an optimized VFP-capable assembly
+# interpreter loop for Dalvik.
+#
+include $(BUILD_COMBOS)/arch/arm/armv5te.mk
+
diff --git a/build/core/combo/arch/arm/armv5te.mk b/build/core/combo/arch/arm/armv5te.mk
new file mode 100644 (file)
index 0000000..29aada6
--- /dev/null
@@ -0,0 +1,21 @@
+# Configuration for Linux on ARM.
+# Generating binaries for the ARMv5TE architecture and higher
+#
+ARCH_ARM_HAVE_THUMB_SUPPORT     := true
+ARCH_ARM_HAVE_FAST_INTERWORKING := true
+ARCH_ARM_HAVE_64BIT_DATA        := true
+ARCH_ARM_HAVE_HALFWORD_MULTIPLY := true
+ARCH_ARM_HAVE_CLZ               := true
+ARCH_ARM_HAVE_FFS               := true
+
+# Note: Hard coding the 'tune' value here is probably not ideal,
+# and a better solution should be found in the future.
+#
+arch_variant_cflags := \
+    -march=armv5te \
+    -mtune=xscale  \
+    -D__ARM_ARCH_5__ \
+    -D__ARM_ARCH_5T__ \
+    -D__ARM_ARCH_5E__ \
+    -D__ARM_ARCH_5TE__
+
diff --git a/build/core/combo/arch/arm/armv7-a-neon.mk b/build/core/combo/arch/arm/armv7-a-neon.mk
new file mode 100644 (file)
index 0000000..7b5b8ed
--- /dev/null
@@ -0,0 +1,24 @@
+# Configuration for Linux on ARM.
+# Generating binaries for the ARMv7-a architecture and higher with NEON
+#
+ARCH_ARM_HAVE_THUMB_SUPPORT     := true
+ARCH_ARM_HAVE_FAST_INTERWORKING := true
+ARCH_ARM_HAVE_64BIT_DATA        := true
+ARCH_ARM_HAVE_HALFWORD_MULTIPLY := true
+ARCH_ARM_HAVE_CLZ               := true
+ARCH_ARM_HAVE_FFS               := true
+ARCH_ARM_HAVE_ARMV7A            := true
+ARCH_ARM_HAVE_VFP               := true
+ARCH_ARM_HAVE_VFP_D32           := true
+ARCH_ARM_HAVE_NEON              := true
+
+# Note: Hard coding the 'tune' value here is probably not ideal,
+# and a better solution should be found in the future.
+#
+arch_variant_cflags := \
+    -march=armv7-a \
+    -mfloat-abi=softfp \
+    -mfpu=neon
+
+arch_variant_ldflags := \
+       -Wl,--fix-cortex-a8
diff --git a/build/core/combo/arch/arm/armv7-a.mk b/build/core/combo/arch/arm/armv7-a.mk
new file mode 100644 (file)
index 0000000..0ca3ec6
--- /dev/null
@@ -0,0 +1,22 @@
+# Configuration for Linux on ARM.
+# Generating binaries for the ARMv7-a architecture and higher
+#
+ARCH_ARM_HAVE_THUMB_SUPPORT     := true
+ARCH_ARM_HAVE_FAST_INTERWORKING := true
+ARCH_ARM_HAVE_64BIT_DATA        := true
+ARCH_ARM_HAVE_HALFWORD_MULTIPLY := true
+ARCH_ARM_HAVE_CLZ               := true
+ARCH_ARM_HAVE_FFS               := true
+ARCH_ARM_HAVE_ARMV7A            := true
+ARCH_ARM_HAVE_VFP               := true
+
+# Note: Hard coding the 'tune' value here is probably not ideal,
+# and a better solution should be found in the future.
+#
+arch_variant_cflags := \
+    -march=armv7-a \
+    -mfloat-abi=softfp \
+    -mfpu=vfpv3-d16
+
+arch_variant_ldflags := \
+       -Wl,--fix-cortex-a8
diff --git a/build/core/combo/javac.mk b/build/core/combo/javac.mk
new file mode 100644 (file)
index 0000000..d4c04e7
--- /dev/null
@@ -0,0 +1,37 @@
+# Selects a Java compiler.
+#
+# Inputs:
+#      CUSTOM_JAVA_COMPILER -- "eclipse", "openjdk". or nothing for the system 
+#                           default
+#
+# Outputs:
+#   COMMON_JAVAC -- Java compiler command with common arguments
+
+# Whatever compiler is on this system.
+ifeq ($(HOST_OS), windows)
+    COMMON_JAVAC := development/host/windows/prebuilt/javawrap.exe -J-Xmx256m \
+        -target 1.5 -Xmaxerrs 9999999
+else
+    COMMON_JAVAC := javac -J-Xmx512M -target 1.5 -Xmaxerrs 9999999
+endif
+
+# Eclipse.
+ifeq ($(CUSTOM_JAVA_COMPILER), eclipse)
+    COMMON_JAVAC := java -Xmx256m -jar prebuilt/common/ecj/ecj.jar -5 \
+        -maxProblems 9999999 -nowarn
+    $(info CUSTOM_JAVA_COMPILER=eclipse)
+endif
+
+# OpenJDK.
+ifeq ($(CUSTOM_JAVA_COMPILER), openjdk)
+    # We set the VM options (like -Xmx) in the javac script.
+    COMMON_JAVAC := prebuilt/common/openjdk/bin/javac -target 1.5 \
+        -Xmaxerrs 9999999
+    $(info CUSTOM_JAVA_COMPILER=openjdk)
+endif
+   
+HOST_JAVAC ?= $(COMMON_JAVAC)
+TARGET_JAVAC ?= $(COMMON_JAVAC)
+    
+#$(info HOST_JAVAC=$(HOST_JAVAC))
+#$(info TARGET_JAVAC=$(TARGET_JAVAC))
diff --git a/build/core/combo/select.mk b/build/core/combo/select.mk
new file mode 100644 (file)
index 0000000..c886342
--- /dev/null
@@ -0,0 +1,74 @@
+#
+# Copyright (C) 2006 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Select a combo based on the compiler being used.
+#
+# Inputs:
+#      combo_target -- prefix for final variables (HOST_ or TARGET_)
+#
+
+# Build a target string like "linux-arm" or "darwin-x86".
+combo_os_arch := $($(combo_target)OS)-$($(combo_target)ARCH)
+
+# Set reasonable defaults for the various variables
+
+$(combo_target)CC := $(CC)
+$(combo_target)CXX := $(CXX)
+$(combo_target)AR := $(AR)
+$(combo_target)STRIP := $(STRIP)
+
+$(combo_target)BINDER_MINI := 0
+
+$(combo_target)HAVE_EXCEPTIONS := 0
+$(combo_target)HAVE_UNIX_FILE_PATH := 1
+$(combo_target)HAVE_WINDOWS_FILE_PATH := 0
+$(combo_target)HAVE_RTTI := 1
+$(combo_target)HAVE_CALL_STACKS := 1
+$(combo_target)HAVE_64BIT_IO := 1
+$(combo_target)HAVE_CLOCK_TIMERS := 1
+$(combo_target)HAVE_PTHREAD_RWLOCK := 1
+$(combo_target)HAVE_STRNLEN := 1
+$(combo_target)HAVE_STRERROR_R_STRRET := 1
+$(combo_target)HAVE_STRLCPY := 0
+$(combo_target)HAVE_STRLCAT := 0
+$(combo_target)HAVE_KERNEL_MODULES := 0
+
+$(combo_target)GLOBAL_CFLAGS := -fno-exceptions -Wno-multichar
+$(combo_target)RELEASE_CFLAGS := -O2 -g -fno-strict-aliasing
+$(combo_target)GLOBAL_LDFLAGS :=
+$(combo_target)GLOBAL_ARFLAGS := crsP
+
+$(combo_target)EXECUTABLE_SUFFIX :=
+$(combo_target)SHLIB_SUFFIX := .so
+$(combo_target)JNILIB_SUFFIX := $($(combo_target)SHLIB_SUFFIX)
+$(combo_target)STATIC_LIB_SUFFIX := .a
+
+$(combo_target)PRELINKER_MAP := $(BUILD_SYSTEM)/prelink-$(combo_os_arch).map
+
+# Now include the combo for this specific target.
+include $(BUILD_COMBOS)/$(combo_target)$(combo_os_arch).mk
+
+ifneq ($(USE_CCACHE),)
+  ccache := prebuilt/$(HOST_PREBUILT_TAG)/ccache/ccache
+  # prepend ccache if necessary
+  ifneq ($(ccache),$(firstword $($(combo_target)CC)))
+    $(combo_target)CC := $(ccache) $($(combo_target)CC)
+  endif
+  ifneq ($(ccache),$(firstword $($(combo_target)CXX)))
+    $(combo_target)CXX := $(ccache) $($(combo_target)CXX)
+  endif
+  ccache =
+endif
diff --git a/build/core/config.mk b/build/core/config.mk
new file mode 100644 (file)
index 0000000..9b588cf
--- /dev/null
@@ -0,0 +1,362 @@
+# This is included by the top-level Makefile.
+# It sets up standard variables based on the
+# current configuration and platform, which
+# are not specific to what is being built.
+
+# Only use ANDROID_BUILD_SHELL to wrap around bash.
+# DO NOT use other shells such as zsh.
+ifdef ANDROID_BUILD_SHELL
+SHELL := $(ANDROID_BUILD_SHELL)
+else
+# Use bash, not whatever shell somebody has installed as /bin/sh
+# This is repeated from main.mk, since envsetup.sh runs this file
+# directly.
+SHELL := /bin/bash
+endif
+
+# Tell python not to spam the source tree with .pyc files.  This
+# only has an effect on python 2.6 and above.
+export PYTHONDONTWRITEBYTECODE := 1
+
+# Standard source directories.
+SRC_DOCS:= $(TOPDIR)docs
+# TODO: Enforce some kind of layering; only add include paths
+#       when a module links against a particular library.
+# TODO: See if we can remove most of these from the global list.
+SRC_HEADERS := \
+       $(TOPDIR)system/core/include \
+       $(TOPDIR)hardware/libhardware/include \
+       $(TOPDIR)hardware/libhardware_legacy/include \
+       $(TOPDIR)hardware/ril/include \
+       $(TOPDIR)dalvik/libnativehelper/include \
+       $(TOPDIR)frameworks/base/include \
+       $(TOPDIR)frameworks/base/opengl/include \
+    $(TOPDIR)frameworks/base/native/include \
+       $(TOPDIR)external/skia/include
+SRC_HOST_HEADERS:=$(TOPDIR)tools/include
+SRC_LIBRARIES:= $(TOPDIR)libs
+SRC_SERVERS:= $(TOPDIR)servers
+SRC_TARGET_DIR := $(TOPDIR)build/target
+SRC_API_DIR := $(TOPDIR)frameworks/base/api
+
+# Some specific paths to tools
+SRC_DROIDDOC_DIR := $(TOPDIR)build/tools/droiddoc
+
+# Various mappings to avoid hard-coding paths all over the place
+include $(BUILD_SYSTEM)/pathmap.mk
+
+# ###############################################################
+# Build system internal files
+# ###############################################################
+
+BUILD_COMBOS:= $(BUILD_SYSTEM)/combo
+
+CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk
+BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk
+BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk
+BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk
+BUILD_RAW_STATIC_LIBRARY := $(BUILD_SYSTEM)/raw_static_library.mk
+BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk
+BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk
+BUILD_RAW_EXECUTABLE:= $(BUILD_SYSTEM)/raw_executable.mk
+BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk
+BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk
+BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk
+BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk
+BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk
+BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk
+BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk
+BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk
+BUILD_DROIDDOC:= $(BUILD_SYSTEM)/droiddoc.mk
+BUILD_COPY_HEADERS := $(BUILD_SYSTEM)/copy_headers.mk
+BUILD_KEY_CHAR_MAP := $(BUILD_SYSTEM)/key_char_map.mk
+
+# ###############################################################
+# Parse out any modifier targets.
+# ###############################################################
+
+# The 'showcommands' goal says to show the full command
+# lines being executed, instead of a short message about
+# the kind of operation being done.
+SHOW_COMMANDS:= $(filter showcommands,$(MAKECMDGOALS))
+
+
+# ###############################################################
+# Set common values
+# ###############################################################
+
+# These can be changed to modify both host and device modules.
+COMMON_GLOBAL_CFLAGS:= -DANDROID -fmessage-length=0 -W -Wall -Wno-unused -Winit-self -Wpointer-arith
+COMMON_RELEASE_CFLAGS:= -DNDEBUG -UDEBUG
+
+COMMON_GLOBAL_CPPFLAGS:= $(COMMON_GLOBAL_CFLAGS) -Wsign-promo
+COMMON_RELEASE_CPPFLAGS:= $(COMMON_RELEASE_CFLAGS)
+
+# Set the extensions used for various packages
+COMMON_PACKAGE_SUFFIX := .zip
+COMMON_JAVA_PACKAGE_SUFFIX := .jar
+COMMON_ANDROID_PACKAGE_SUFFIX := .apk
+
+# list of flags to turn specific warnings in to errors
+TARGET_ERROR_FLAGS := -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point
+
+# TODO: do symbol compression
+TARGET_COMPRESS_MODULE_SYMBOLS := false
+
+# Default is to prelink modules.
+TARGET_PRELINK_MODULE := true
+
+# Default shell is ash. Other possible value is mksh.
+TARGET_SHELL := ash
+
+# ###############################################################
+# Include sub-configuration files
+# ###############################################################
+
+# ---------------------------------------------------------------
+# Try to include buildspec.mk, which will try to set stuff up.
+# If this file doesn't exist, the environemnt variables will
+# be used, and if that doesn't work, then the default is an
+# arm build
+-include $(TOPDIR)buildspec.mk
+
+# ---------------------------------------------------------------
+# Define most of the global variables.  These are the ones that
+# are specific to the user's build configuration.
+include $(BUILD_SYSTEM)/envsetup.mk
+
+# Boards may be defined under $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)
+# or under vendor/*/$(TARGET_DEVICE).  Search in both places, but
+# make sure only one exists.
+# Real boards should always be associated with an OEM vendor.
+board_config_mk := \
+       $(strip $(wildcard \
+               $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \
+               device/*/$(TARGET_DEVICE)/BoardConfig.mk \
+               vendor/*/$(TARGET_DEVICE)/BoardConfig.mk \
+       ))
+ifeq ($(board_config_mk),)
+  $(error No config file found for TARGET_DEVICE $(TARGET_DEVICE))
+endif
+ifneq ($(words $(board_config_mk)),1)
+  $(error Multiple board config files for TARGET_DEVICE $(TARGET_DEVICE): $(board_config_mk))
+endif
+include $(board_config_mk)
+TARGET_DEVICE_DIR := $(patsubst %/,%,$(dir $(board_config_mk)))
+board_config_mk :=
+
+# Clean up/verify variables defined by the board config file.
+TARGET_BOOTLOADER_BOARD_NAME := $(strip $(TARGET_BOOTLOADER_BOARD_NAME))
+TARGET_CPU_ABI := $(strip $(TARGET_CPU_ABI))
+ifeq ($(TARGET_CPU_ABI),)
+  $(error No TARGET_CPU_ABI defined by board config: $(board_config_mk))
+endif
+TARGET_CPU_ABI2 := $(strip $(TARGET_CPU_ABI2))
+
+# $(1): os/arch
+define select-android-config-h
+system/core/include/arch/$(1)/AndroidConfig.h
+endef
+
+combo_target := HOST_
+include $(BUILD_SYSTEM)/combo/select.mk
+
+# on windows, the tools have .exe at the end, and we depend on the
+# host config stuff being done first
+
+combo_target := TARGET_
+include $(BUILD_SYSTEM)/combo/select.mk
+
+# Pick a Java compiler.
+include $(BUILD_SYSTEM)/combo/javac.mk
+
+# ---------------------------------------------------------------
+# Check that the configuration is current.  We check that
+# BUILD_ENV_SEQUENCE_NUMBER is current against this value.
+# Don't fail if we're called from envsetup, so they have a
+# chance to update their environment.
+
+ifeq (,$(strip $(CALLED_FROM_SETUP)))
+ifneq (,$(strip $(BUILD_ENV_SEQUENCE_NUMBER)))
+ifneq ($(BUILD_ENV_SEQUENCE_NUMBER),$(CORRECT_BUILD_ENV_SEQUENCE_NUMBER))
+$(warning BUILD_ENV_SEQUENCE_NUMBER is set incorrectly.)
+$(info *** If you use envsetup/lunch/choosecombo:)
+$(info ***   - Re-execute envsetup (". envsetup.sh"))
+$(info ***   - Re-run lunch or choosecombo)
+$(info *** If you use buildspec.mk:)
+$(info ***   - Look at buildspec.mk.default to see what has changed)
+$(info ***   - Update BUILD_ENV_SEQUENCE_NUMBER to "$(CORRECT_BUILD_ENV_SEQUENCE_NUMBER)")
+$(error bailing..)
+endif
+endif
+endif
+
+
+# ---------------------------------------------------------------
+# Generic tools.
+
+LEX:= flex
+YACC:= bison -d
+DOXYGEN:= doxygen
+AAPT := $(HOST_OUT_EXECUTABLES)/aapt$(HOST_EXECUTABLE_SUFFIX)
+AIDL := $(HOST_OUT_EXECUTABLES)/aidl$(HOST_EXECUTABLE_SUFFIX)
+PROTOC := $(HOST_OUT_EXECUTABLES)/aprotoc$(HOST_EXECUTABLE_SUFFIX)
+ICUDATA := $(HOST_OUT_EXECUTABLES)/icudata$(HOST_EXECUTABLE_SUFFIX)
+SIGNAPK_JAR := $(HOST_OUT_JAVA_LIBRARIES)/signapk$(COMMON_JAVA_PACKAGE_SUFFIX)
+MKBOOTFS := $(HOST_OUT_EXECUTABLES)/mkbootfs$(HOST_EXECUTABLE_SUFFIX)
+MINIGZIP := $(HOST_OUT_EXECUTABLES)/minigzip$(HOST_EXECUTABLE_SUFFIX)
+MKBOOTIMG := $(HOST_OUT_EXECUTABLES)/mkbootimg$(HOST_EXECUTABLE_SUFFIX)
+MKYAFFS2 := $(HOST_OUT_EXECUTABLES)/mkyaffs2image$(HOST_EXECUTABLE_SUFFIX)
+APICHECK := $(HOST_OUT_EXECUTABLES)/apicheck$(HOST_EXECUTABLE_SUFFIX)
+FS_GET_STATS := $(HOST_OUT_EXECUTABLES)/fs_get_stats$(HOST_EXECUTABLE_SUFFIX)
+MKEXT2IMG := $(HOST_OUT_EXECUTABLES)/genext2fs$(HOST_EXECUTABLE_SUFFIX)
+MAKE_EXT4FS := $(HOST_OUT_EXECUTABLES)/make_ext4fs$(HOST_EXECUTABLE_SUFFIX)
+MKEXTUSERIMG := $(HOST_OUT_EXECUTABLES)/mkuserimg.sh
+MKEXT2BOOTIMG := external/genext2fs/mkbootimg_ext2.sh
+MKTARBALL := build/tools/mktarball.sh
+TUNE2FS := tune2fs
+E2FSCK := e2fsck
+JARJAR := $(HOST_OUT_JAVA_LIBRARIES)/jarjar.jar
+PROGUARD := external/proguard/bin/proguard.sh
+JAVATAGS := build/tools/java-event-log-tags.py
+DEXOPT := $(HOST_OUT_EXECUTABLES)/dexopt$(HOST_EXECUTABLE_SUFFIX)
+DEXPREOPT := dalvik/tools/dex-preopt
+
+# ACP is always for the build OS, not for the host OS
+ACP := $(BUILD_OUT_EXECUTABLES)/acp$(BUILD_EXECUTABLE_SUFFIX)
+
+# dx is java behind a shell script; no .exe necessary.
+DX := $(HOST_OUT_EXECUTABLES)/dx
+KCM := $(HOST_OUT_EXECUTABLES)/kcm$(HOST_EXECUTABLE_SUFFIX)
+ZIPALIGN := $(HOST_OUT_EXECUTABLES)/zipalign$(HOST_EXECUTABLE_SUFFIX)
+FINDBUGS := prebuilt/common/findbugs/bin/findbugs
+LOCALIZE := $(HOST_OUT_EXECUTABLES)/localize$(HOST_EXECUTABLE_SUFFIX)
+EMMA_JAR := external/emma/lib/emma$(COMMON_JAVA_PACKAGE_SUFFIX)
+
+# Binary prelinker/compressor tools
+APRIORI := $(HOST_OUT_EXECUTABLES)/apriori$(HOST_EXECUTABLE_SUFFIX)
+LSD := $(HOST_OUT_EXECUTABLES)/lsd$(HOST_EXECUTABLE_SUFFIX)
+
+# Deal with archaic version of bison on Mac OS X.
+ifeq ($(filter 1.28,$(shell $(YACC) -V)),)
+YACC_HEADER_SUFFIX:= .hpp
+else
+YACC_HEADER_SUFFIX:= .cpp.h
+endif
+
+# Don't use column under Windows, cygwin or not
+ifeq ($(HOST_OS),windows)
+COLUMN:= cat
+else
+COLUMN:= column
+endif
+
+dir := $(shell uname)
+ifeq ($(HOST_OS),windows)
+dir := $(HOST_OS)
+endif
+ifeq ($(HOST_OS),darwin)
+dir := $(HOST_OS)-$(HOST_ARCH)
+endif
+OLD_FLEX := prebuilt/$(HOST_PREBUILT_TAG)/flex/flex-2.5.4a$(HOST_EXECUTABLE_SUFFIX)
+
+ifeq ($(HOST_OS),darwin)
+# Mac OS' screwy version of java uses a non-standard directory layout
+# and doesn't even seem to have tools.jar.  On the other hand, javac seems
+# to be able to magically find the classes in there, wherever they are, so
+# leave this blank
+HOST_JDK_TOOLS_JAR :=
+else
+HOST_JDK_TOOLS_JAR:= $(shell $(BUILD_SYSTEM)/find-jdk-tools-jar.sh)
+endif
+
+# It's called md5 on Mac OS and md5sum on Linux
+ifeq ($(HOST_OS),darwin)
+MD5SUM:=md5 -q
+else
+MD5SUM:=md5sum
+endif
+
+# ###############################################################
+# Set up final options.
+# ###############################################################
+
+HOST_GLOBAL_CFLAGS += $(COMMON_GLOBAL_CFLAGS)
+HOST_RELEASE_CFLAGS += $(COMMON_RELEASE_CFLAGS)
+
+HOST_GLOBAL_CPPFLAGS += $(COMMON_GLOBAL_CPPFLAGS)
+HOST_RELEASE_CPPFLAGS += $(COMMON_RELEASE_CPPFLAGS)
+
+TARGET_GLOBAL_CFLAGS += $(COMMON_GLOBAL_CFLAGS)
+TARGET_RELEASE_CFLAGS += $(COMMON_RELEASE_CFLAGS)
+
+TARGET_GLOBAL_CPPFLAGS += $(COMMON_GLOBAL_CPPFLAGS)
+TARGET_RELEASE_CPPFLAGS += $(COMMON_RELEASE_CPPFLAGS)
+
+HOST_GLOBAL_LD_DIRS += -L$(HOST_OUT_INTERMEDIATE_LIBRARIES)
+TARGET_GLOBAL_LD_DIRS += -L$(TARGET_OUT_INTERMEDIATE_LIBRARIES)
+
+HOST_PROJECT_INCLUDES:= $(SRC_HEADERS) $(SRC_HOST_HEADERS) $(HOST_OUT_HEADERS)
+TARGET_PROJECT_INCLUDES:= $(SRC_HEADERS) $(TARGET_OUT_HEADERS)
+
+# Many host compilers don't support these flags, so we have to make
+# sure to only specify them for the target compilers checked in to
+# the source tree. The simulator passes the target flags to the
+# host compiler, so only set them for the target when the target
+# is not the simulator.
+ifneq ($(TARGET_SIMULATOR),true)
+TARGET_GLOBAL_CFLAGS += $(TARGET_ERROR_FLAGS)
+TARGET_GLOBAL_CPPFLAGS += $(TARGET_ERROR_FLAGS)
+endif
+
+HOST_GLOBAL_CFLAGS += $(HOST_RELEASE_CFLAGS)
+HOST_GLOBAL_CPPFLAGS += $(HOST_RELEASE_CPPFLAGS)
+
+TARGET_GLOBAL_CFLAGS += $(TARGET_RELEASE_CFLAGS)
+TARGET_GLOBAL_CPPFLAGS += $(TARGET_RELEASE_CPPFLAGS)
+
+PREBUILT_IS_PRESENT := $(if $(wildcard prebuilt/Android.mk),true)
+
+# ###############################################################
+# Collect a list of the SDK versions that we could compile against
+# For use with the LOCAL_SDK_VERSION variable for include $(BUILD_PACKAGE)
+# ###############################################################
+
+HISTORICAL_SDK_VERSIONS_ROOT := $(TOPDIR)prebuilt/sdk
+HISTORICAL_NDK_VERSIONS_ROOT := $(TOPDIR)prebuilt/ndk
+
+# Historical SDK version N is stored in $(HISTORICAL_SDK_VERSIONS_ROOT)/N.
+# The 'current' version is whatever this source tree is.
+#
+# sgrax     is the opposite of xargs.  It takes the list of args and puts them
+#           on each line for sort to process.
+# sort -g   is a numeric sort, so 1 2 3 10 instead of 1 10 2 3.
+
+# Numerically sort a list of numbers
+# $(1): the list of numbers to be sorted
+define numerically_sort
+$(shell function sgrax() { \
+    while [ -n "$$1" ] ; do echo $$1 ; shift ; done \
+    } ; \
+    ( sgrax $(1) | sort -g ) )
+endef
+
+TARGET_AVAILABLE_SDK_VERSIONS := current $(call numerically_sort,\
+    $(patsubst $(HISTORICAL_SDK_VERSIONS_ROOT)/%/android.jar,%, \
+    $(wildcard $(HISTORICAL_SDK_VERSIONS_ROOT)/*/android.jar)))
+
+TARGET_AVAILABLE_NDK_VERSIONS := $(call numerically_sort,\
+    $(patsubst $(HISTORICAL_NDK_VERSIONS_ROOT)/android-ndk-r%,%, \
+    $(wildcard $(HISTORICAL_NDK_VERSIONS_ROOT)/android-ndk-r*)))
+
+INTERNAL_PLATFORM_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/public_api.xml
+
+# This is the standard way to name a directory containing prebuilt target
+# objects. E.g., prebuilt/$(TARGET_PREBUILT_TAG)/libc.so
+ifeq ($(TARGET_SIMULATOR),true)
+  TARGET_PREBUILT_TAG := $(TARGET_OS)-$(TARGET_ARCH)
+else
+  TARGET_PREBUILT_TAG := android-$(TARGET_ARCH)
+endif
+
+include $(BUILD_SYSTEM)/dumpvar.mk
diff --git a/build/core/copy_headers.mk b/build/core/copy_headers.mk
new file mode 100644 (file)
index 0000000..dac07d5
--- /dev/null
@@ -0,0 +1,23 @@
+###########################################################
+## Copy headers to the install tree
+###########################################################
+ifneq ($(strip $(LOCAL_IS_HOST_MODULE)),)
+  my_prefix := HOST_
+else
+  my_prefix := TARGET_
+endif
+
+# Create a rule to copy each header, and make the
+# all_copied_headers phony target depend on each
+# destination header.  copy-one-header defines the
+# actual rule.
+#
+$(foreach header,$(LOCAL_COPY_HEADERS), \
+  $(eval _chFrom := $(LOCAL_PATH)/$(header)) \
+  $(eval _chTo := \
+      $($(my_prefix)OUT_HEADERS)/$(LOCAL_COPY_HEADERS_TO)/$(notdir $(header))) \
+  $(eval $(call copy-one-header,$(_chFrom),$(_chTo))) \
+  $(eval all_copied_headers: $(_chTo)) \
+ )
+_chFrom :=
+_chTo :=
diff --git a/build/core/definitions.mk b/build/core/definitions.mk
new file mode 100644 (file)
index 0000000..36285b8
--- /dev/null
@@ -0,0 +1,1869 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##
+## Common build system definitions.  Mostly standard
+## commands for building various types of targets, which
+## are used by others to construct the final targets.
+##
+
+# These are variables we use to collect overall lists
+# of things being processed.
+
+# Full paths to all of the documentation
+ALL_DOCS:=
+
+# The short names of all of the targets in the system.
+# For each element of ALL_MODULES, two other variables
+# are defined:
+#   $(ALL_MODULES.$(target)).BUILT
+#   $(ALL_MODULES.$(target)).INSTALLED
+# The BUILT variable contains LOCAL_BUILT_MODULE for that
+# target, and the INSTALLED variable contains the LOCAL_INSTALLED_MODULE.
+# Some targets may have multiple files listed in the BUILT and INSTALLED
+# sub-variables.
+ALL_MODULES:=
+
+# Full paths to targets that should be added to the "make droid"
+# set of installed targets.
+ALL_DEFAULT_INSTALLED_MODULES:=
+
+# The list of tags that have been defined by
+# LOCAL_MODULE_TAGS.  Each word in this variable maps
+# to a corresponding ALL_MODULE_TAGS.<tagname> variable
+# that contains all of the INSTALLED_MODULEs with that tag.
+ALL_MODULE_TAGS:=
+
+# Similar to ALL_MODULE_TAGS, but contains the short names
+# of all targets for a particular tag.  The top-level variable
+# won't have the list of tags;  ust ALL_MODULE_TAGS to get
+# the list of all known tags.  (This means that this variable
+# will always be empty; it's just here as a placeholder for
+# its sub-variables.)
+ALL_MODULE_NAME_TAGS:=
+
+# Full paths to all prebuilt files that will be copied
+# (used to make the dependency on acp)
+ALL_PREBUILT:=
+
+# Full path to all files that are made by some tool
+ALL_GENERATED_SOURCES:=
+
+# Full path to all asm, C, C++, lex and yacc generated C files.
+# These all have an order-only dependency on the copied headers
+ALL_C_CPP_ETC_OBJECTS:=
+
+# The list of dynamic binaries that haven't been stripped/compressed/prelinked.
+ALL_ORIGINAL_DYNAMIC_BINARIES:=
+
+# These files go into the SDK
+ALL_SDK_FILES:=
+
+# Files for dalvik.  This is often build without building the rest of the OS.
+INTERNAL_DALVIK_MODULES:=
+
+# All findbugs xml files
+ALL_FINDBUGS_FILES:=
+
+###########################################################
+## Debugging; prints a variable list to stdout
+###########################################################
+
+# $(1): variable name list, not variable values
+define print-vars
+$(foreach var,$(1), \
+  $(info $(var):) \
+  $(foreach word,$($(var)), \
+    $(info $(space)$(space)$(word)) \
+   ) \
+ )
+endef
+
+###########################################################
+## Evaluates to true if the string contains the word true,
+## and empty otherwise
+## $(1): a var to test
+###########################################################
+
+define true-or-empty
+$(filter true, $(1))
+endef
+
+
+###########################################################
+## Retrieve the directory of the current makefile
+###########################################################
+
+# Figure out where we are.
+define my-dir
+$(strip \
+  $(eval md_file_ := $$(lastword $$(MAKEFILE_LIST))) \
+  $(if $(filter $(CLEAR_VARS),$(md_file_)), \
+    $(error LOCAL_PATH must be set before including $$(CLEAR_VARS)) \
+   , \
+    $(patsubst %/,%,$(dir $(md_file_))) \
+   ) \
+ )
+endef
+
+###########################################################
+## Retrieve a list of all makefiles immediately below some directory
+###########################################################
+
+define all-makefiles-under
+$(wildcard $(1)/*/Android.mk)
+endef
+
+###########################################################
+## Look under a directory for makefiles that don't have parent
+## makefiles.
+###########################################################
+
+# $(1): directory to search under
+# Ignores $(1)/Android.mk
+define first-makefiles-under
+$(shell build/tools/findleaves.py --prune=out --prune=.repo --prune=.git \
+        --mindepth=2 $(1) Android.mk)
+endef
+
+###########################################################
+## Retrieve a list of all makefiles immediately below your directory
+###########################################################
+
+define all-subdir-makefiles
+$(call all-makefiles-under,$(call my-dir))
+endef
+
+###########################################################
+## Look in the named list of directories for makefiles,
+## relative to the current directory.
+###########################################################
+
+# $(1): List of directories to look for under this directory
+define all-named-subdir-makefiles
+$(wildcard $(addsuffix /Android.mk, $(addprefix $(my-dir)/,$(1))))
+endef
+
+###########################################################
+## Find all of the java files under the named directories.
+## Meant to be used like:
+##    SRC_FILES := $(call all-java-files-under,src tests)
+###########################################################
+
+define all-java-files-under
+$(patsubst ./%,%, \
+  $(shell cd $(LOCAL_PATH) ; \
+          find $(1) -name "*.java" -and -not -name ".*") \
+ )
+endef
+
+###########################################################
+## Find all of the java files from here.  Meant to be used like:
+##    SRC_FILES := $(call all-subdir-java-files)
+###########################################################
+
+define all-subdir-java-files
+$(call all-java-files-under,.)
+endef
+
+###########################################################
+## Find all of the c files under the named directories.
+## Meant to be used like:
+##    SRC_FILES := $(call all-c-files-under,src tests)
+###########################################################
+
+define all-c-files-under
+$(patsubst ./%,%, \
+  $(shell cd $(LOCAL_PATH) ; \
+          find $(1) -name "*.c" -and -not -name ".*") \
+ )
+endef
+
+###########################################################
+## Find all of the c files from here.  Meant to be used like:
+##    SRC_FILES := $(call all-subdir-c-files)
+###########################################################
+
+define all-subdir-c-files
+$(call all-c-files-under,.)
+endef
+
+###########################################################
+## Find all files named "I*.aidl" under the named directories,
+## which must be relative to $(LOCAL_PATH).  The returned list
+## is relative to $(LOCAL_PATH).
+###########################################################
+
+define all-Iaidl-files-under
+$(patsubst ./%,%, \
+  $(shell cd $(LOCAL_PATH) ; \
+          find $(1) -name "I*.aidl" -and -not -name ".*") \
+ )
+endef
+
+###########################################################
+## Find all of the "I*.aidl" files under $(LOCAL_PATH).
+###########################################################
+
+define all-subdir-Iaidl-files
+$(call all-Iaidl-files-under,.)
+endef
+
+###########################################################
+## Find all of the logtags files under the named directories.
+## Meant to be used like:
+##    SRC_FILES := $(call all-logtags-files-under,src)
+###########################################################
+
+define all-logtags-files-under
+$(patsubst ./%,%, \
+  $(shell cd $(LOCAL_PATH) ; \
+          find $(1) -name "*.logtags" -and -not -name ".*") \
+  )
+endef
+
+###########################################################
+## Find all of the .proto files under the named directories.
+## Meant to be used like:
+##    SRC_FILES := $(call all-proto-files-under,src)
+###########################################################
+
+define all-proto-files-under
+$(patsubst ./%,%, \
+  $(shell cd $(LOCAL_PATH) ; \
+          find $(1) -name "*.proto" -and -not -name ".*") \
+  )
+endef
+
+###########################################################
+## Find all of the html files under the named directories.
+## Meant to be used like:
+##    SRC_FILES := $(call all-html-files-under,src tests)
+###########################################################
+
+define all-html-files-under
+$(patsubst ./%,%, \
+  $(shell cd $(LOCAL_PATH) ; \
+          find $(1) -name "*.html" -and -not -name ".*") \
+ )
+endef
+
+###########################################################
+## Find all of the html files from here.  Meant to be used like:
+##    SRC_FILES := $(call all-subdir-html-files)
+###########################################################
+
+define all-subdir-html-files
+$(call all-html-files-under,.)
+endef
+
+###########################################################
+## Find all of the files matching pattern
+##    SRC_FILES := $(call find-subdir-files, <pattern>)
+###########################################################
+
+define find-subdir-files
+$(patsubst ./%,%,$(shell cd $(LOCAL_PATH) ; find $(1)))
+endef
+
+###########################################################
+# find the files in the subdirectory $1 of LOCAL_DIR
+# matching pattern $2, filtering out files $3
+# e.g.
+#     SRC_FILES += $(call find-subdir-subdir-files, \
+#                         css, *.cpp, DontWantThis.cpp)
+###########################################################
+
+define find-subdir-subdir-files
+$(filter-out $(patsubst %,$(1)/%,$(3)),$(patsubst ./%,%,$(shell cd \
+            $(LOCAL_PATH) ; find $(1) -maxdepth 1 -name $(2))))
+endef
+
+###########################################################
+## Find all of the files matching pattern
+##    SRC_FILES := $(call all-subdir-java-files)
+###########################################################
+
+define find-subdir-assets
+$(if $(1),$(patsubst ./%,%, \
+       $(shell if [ -d $(1) ] ; then cd $(1) ; find ./ -type f -and -not -type l ; fi)), \
+       $(warning Empty argument supplied to find-subdir-assets) \
+)
+endef
+
+###########################################################
+## Find various file types in a list of directories relative to $(LOCAL_PATH)
+###########################################################
+
+define find-other-java-files
+       $(call find-subdir-files,$(1) -name "*.java" -and -not -name ".*")
+endef
+
+define find-other-html-files
+       $(call find-subdir-files,$(1) -name "*.html" -and -not -name ".*")
+endef
+
+###########################################################
+## Scan through each directory of $(1) looking for files
+## that match $(2) using $(wildcard).  Useful for seeing if
+## a given directory or one of its parents contains
+## a particular file.  Returns the first match found,
+## starting furthest from the root.
+###########################################################
+
+define find-parent-file
+$(strip \
+  $(eval _fpf := $(wildcard $(strip $(1))/$(strip $(2)))) \
+  $(if $(_fpf),$(_fpf), \
+       $(if $(filter-out ./ .,$(1)), \
+             $(call find-parent-file,$(patsubst %/,%,$(dir $(1))),$(2)) \
+        ) \
+   ) \
+)
+endef
+
+###########################################################
+## Function we can evaluate to introduce a dynamic dependency
+###########################################################
+
+define add-dependency
+$(1): $(2)
+endef
+
+###########################################################
+## Set up the dependencies for a prebuilt target
+##  $(call add-prebuilt-file, srcfile, [targetclass])
+###########################################################
+
+define add-prebuilt-file
+    $(eval $(include-prebuilt))
+endef
+
+define include-prebuilt
+    include $$(CLEAR_VARS)
+    LOCAL_SRC_FILES := $(1)
+    LOCAL_BUILT_MODULE_STEM := $(1)
+    LOCAL_MODULE_SUFFIX := $$(suffix $(1))
+    LOCAL_MODULE := $$(basename $(1))
+    LOCAL_MODULE_CLASS := $(2)
+    include $$(BUILD_PREBUILT)
+endef
+
+###########################################################
+## do multiple prebuilts
+##  $(call target class, files ...)
+###########################################################
+
+define add-prebuilt-files
+    $(foreach f,$(2),$(call add-prebuilt-file,$f,$(1)))
+endef
+
+
+
+###########################################################
+## The intermediates directory.  Where object files go for
+## a given target.  We could technically get away without
+## the "_intermediates" suffix on the directory, but it's
+## nice to be able to grep for that string to find out if
+## anyone's abusing the system.
+###########################################################
+
+# $(1): target class, like "APPS"
+# $(2): target name, like "NotePad"
+# $(3): if non-empty, this is a HOST target.
+# $(4): if non-empty, force the intermediates to be COMMON
+define intermediates-dir-for
+$(strip \
+    $(eval _idfClass := $(strip $(1))) \
+    $(if $(_idfClass),, \
+        $(error $(LOCAL_PATH): Class not defined in call to intermediates-dir-for)) \
+    $(eval _idfName := $(strip $(2))) \
+    $(if $(_idfName),, \
+        $(error $(LOCAL_PATH): Name not defined in call to intermediates-dir-for)) \
+    $(eval _idfPrefix := $(if $(strip $(3)),HOST,TARGET)) \
+    $(if $(filter $(_idfPrefix)-$(_idfClass),$(COMMON_MODULE_CLASSES))$(4), \
+        $(eval _idfIntBase := $($(_idfPrefix)_OUT_COMMON_INTERMEDIATES)) \
+      , \
+        $(eval _idfIntBase := $($(_idfPrefix)_OUT_INTERMEDIATES)) \
+     ) \
+    $(_idfIntBase)/$(_idfClass)/$(_idfName)_intermediates \
+)
+endef
+
+# Uses LOCAL_MODULE_CLASS, LOCAL_MODULE, and LOCAL_IS_HOST_MODULE
+# to determine the intermediates directory.
+#
+# $(1): if non-empty, force the intermediates to be COMMON
+define local-intermediates-dir
+$(strip \
+    $(if $(strip $(LOCAL_MODULE_CLASS)),, \
+        $(error $(LOCAL_PATH): LOCAL_MODULE_CLASS not defined before call to local-intermediates-dir)) \
+    $(if $(strip $(LOCAL_MODULE)),, \
+        $(error $(LOCAL_PATH): LOCAL_MODULE not defined before call to local-intermediates-dir)) \
+    $(call intermediates-dir-for,$(LOCAL_MODULE_CLASS),$(LOCAL_MODULE),$(LOCAL_IS_HOST_MODULE),$(1)) \
+)
+endef
+
+###########################################################
+## Convert "path/to/libXXX.so" to "-lXXX".
+## Any "path/to/libXXX.a" elements pass through unchanged.
+###########################################################
+
+define normalize-libraries
+$(foreach so,$(filter %.so,$(1)),-l$(patsubst lib%.so,%,$(notdir $(so))))\
+$(filter-out %.so,$(1))
+endef
+
+# TODO: change users to call the common version.
+define normalize-host-libraries
+$(call normalize-libraries,$(1))
+endef
+
+define normalize-target-libraries
+$(call normalize-libraries,$(1))
+endef
+
+###########################################################
+## Convert a list of short module names (e.g., "framework", "Browser")
+## into the list of files that are built for those modules.
+## NOTE: this won't return reliable results until after all
+## sub-makefiles have been included.
+## $(1): target list
+###########################################################
+
+define module-built-files
+$(foreach module,$(1),$(ALL_MODULES.$(module).BUILT))
+endef
+
+###########################################################
+## Convert a list of short modules names (e.g., "framework", "Browser")
+## into the list of files that are installed for those modules.
+## NOTE: this won't return reliable results until after all
+## sub-makefiles have been included.
+## $(1): target list
+###########################################################
+
+define module-installed-files
+$(foreach module,$(1),$(ALL_MODULES.$(module).INSTALLED))
+endef
+
+###########################################################
+## Convert a list of short modules names (e.g., "framework", "Browser")
+## into the list of files that should be used when linking
+## against that module as a public API.
+## TODO: Allow this for more than JAVA_LIBRARIES modules
+## NOTE: this won't return reliable results until after all
+## sub-makefiles have been included.
+## $(1): target list
+###########################################################
+
+define module-stubs-files
+$(foreach module,$(1),$(ALL_MODULES.$(module).STUBS))
+endef
+
+###########################################################
+## Evaluates to the timestamp file for a doc module, which
+## is the dependency that should be used.
+## $(1): doc module
+###########################################################
+
+define doc-timestamp-for
+$(OUT_DOCS)/$(strip $(1))-timestamp
+endef
+
+
+###########################################################
+## Convert "core ext framework" to "out/.../javalib.jar ..."
+## $(1): library list
+## $(2): Non-empty if IS_HOST_MODULE
+###########################################################
+
+# $(1): library name
+# $(2): Non-empty if IS_HOST_MODULE
+define _java-lib-dir
+$(call intermediates-dir-for, \
+       JAVA_LIBRARIES,$(1),$(2),COMMON)
+endef
+
+# $(1): library name
+# $(2): Non-empty if IS_HOST_MODULE
+define _java-lib-full-classes.jar
+$(call _java-lib-dir,$(1),$(2))/classes$(COMMON_JAVA_PACKAGE_SUFFIX)
+endef
+
+# $(1): library name list
+# $(2): Non-empty if IS_HOST_MODULE
+define java-lib-files
+$(foreach lib,$(1),$(call _java-lib-full-classes.jar,$(lib),$(2)))
+endef
+
+# $(1): library name
+# $(2): Non-empty if IS_HOST_MODULE
+define _java-lib-full-dep
+$(call _java-lib-dir,$(1),$(2))/javalib$(COMMON_JAVA_PACKAGE_SUFFIX)
+endef
+
+# $(1): library name list
+# $(2): Non-empty if IS_HOST_MODULE
+define java-lib-deps
+$(foreach lib,$(1),$(call _java-lib-full-dep,$(lib),$(2)))
+endef
+
+###########################################################
+## Convert "a b c" into "a:b:c"
+###########################################################
+
+empty :=
+space := $(empty) $(empty)
+
+define normalize-path-list
+$(subst $(space),:,$(strip $(1)))
+endef
+
+###########################################################
+## Read the word out of a colon-separated list of words.
+## This has the same behavior as the built-in function
+## $(word n,str).
+##
+## The individual words may not contain spaces.
+##
+## $(1): 1 based index
+## $(2): value of the form a:b:c...
+###########################################################
+
+define word-colon
+$(word $(1),$(subst :,$(space),$(2)))
+endef
+
+###########################################################
+## Convert "a=b c= d e = f" into "a=b c=d e=f"
+##
+## $(1): list to collapse
+## $(2): if set, separator word; usually "=", ":", or ":="
+##       Defaults to "=" if not set.
+###########################################################
+
+define collapse-pairs
+$(eval _cpSEP := $(strip $(if $(2),$(2),=)))\
+$(subst $(space)$(_cpSEP)$(space),$(_cpSEP),$(strip \
+    $(subst $(_cpSEP), $(_cpSEP) ,$(1))))
+endef
+
+###########################################################
+## MODULE_TAG set operations
+###########################################################
+
+# Given a list of tags, return the targets that specify
+# any of those tags.
+# $(1): tag list
+define modules-for-tag-list
+$(sort $(foreach tag,$(1),$(ALL_MODULE_TAGS.$(tag))))
+endef
+
+# Same as modules-for-tag-list, but operates on
+# ALL_MODULE_NAME_TAGS.
+# $(1): tag list
+define module-names-for-tag-list
+$(sort $(foreach tag,$(1),$(ALL_MODULE_NAME_TAGS.$(tag))))
+endef
+
+# Given an accept and reject list, find the matching
+# set of targets.  If a target has multiple tags and
+# any of them are rejected, the target is rejected.
+# Reject overrides accept.
+# $(1): list of tags to accept
+# $(2): list of tags to reject
+#TODO(dbort): do $(if $(strip $(1)),$(1),$(ALL_MODULE_TAGS))
+#TODO(jbq): as of 20100106 nobody uses the second parameter
+define get-tagged-modules
+$(filter-out \
+       $(call modules-for-tag-list,$(2)), \
+           $(call modules-for-tag-list,$(1)))
+endef
+
+###########################################################
+## Append a leaf to a base path.  Properly deals with
+## base paths ending in /.
+##
+## $(1): base path
+## $(2): leaf path
+###########################################################
+
+define append-path
+$(subst //,/,$(1)/$(2))
+endef
+
+
+###########################################################
+## Package filtering
+###########################################################
+
+# Given a list of installed modules (short or long names)
+# return a list of the packages (yes, .apk packages, not
+# modules in general) that are overridden by this list and,
+# therefore, should not be installed.
+# $(1): mixed list of installed modules
+# TODO: This is fragile; find a reliable way to get this information.
+define _get-package-overrides
+ $(eval ### Discard any words containing slashes, unless they end in .apk, \
+        ### in which case trim off the directory component and the suffix. \
+        ### If there are no slashes, keep the entire word.)
+ $(eval _gpo_names := $(subst /,@@@ @@@,$(1)))
+ $(eval _gpo_names := \
+     $(filter %.apk,$(_gpo_names)) \
+     $(filter-out %@@@ @@@%,$(_gpo_names)))
+ $(eval _gpo_names := $(patsubst %.apk,%,$(_gpo_names)))
+ $(eval _gpo_names := $(patsubst @@@%,%,$(_gpo_names)))
+
+ $(eval ### Remove any remaining words that contain dots.)
+ $(eval _gpo_names := $(subst .,@@@ @@@,$(_gpo_names)))
+ $(eval _gpo_names := $(filter-out %@@@ @@@%,$(_gpo_names)))
+
+ $(eval ### Now we have a list of any words that could possibly refer to \
+        ### packages, although there may be words that do not.  Only \
+        ### real packages will be present under PACKAGES.*, though.)
+ $(foreach _gpo_name,$(_gpo_names),$(PACKAGES.$(_gpo_name).OVERRIDES))
+endef
+
+define get-package-overrides
+$(strip $(sort $(call _get-package-overrides,$(1))))
+endef
+
+###########################################################
+## Output the command lines, or not
+###########################################################
+
+ifeq ($(strip $(SHOW_COMMANDS)),)
+define pretty
+@echo $1
+endef
+hide := @
+else
+define pretty
+endef
+hide :=
+endif
+
+###########################################################
+## Dump the variables that are associated with targets
+###########################################################
+
+define dump-module-variables
+@echo all_dependencies=$^
+@echo PRIVATE_YACCFLAGS=$(PRIVATE_YACCFLAGS);
+@echo PRIVATE_CFLAGS=$(PRIVATE_CFLAGS);
+@echo PRIVATE_CPPFLAGS=$(PRIVATE_CPPFLAGS);
+@echo PRIVATE_DEBUG_CFLAGS=$(PRIVATE_DEBUG_CFLAGS);
+@echo PRIVATE_C_INCLUDES=$(PRIVATE_C_INCLUDES);
+@echo PRIVATE_LDFLAGS=$(PRIVATE_LDFLAGS);
+@echo PRIVATE_LDLIBS=$(PRIVATE_LDLIBS);
+@echo PRIVATE_ARFLAGS=$(PRIVATE_ARFLAGS);
+@echo PRIVATE_AAPT_FLAGS=$(PRIVATE_AAPT_FLAGS);
+@echo PRIVATE_DX_FLAGS=$(PRIVATE_DX_FLAGS);
+@echo PRIVATE_JAVACFLAGS=$(PRIVATE_JAVACFLAGS);
+@echo PRIVATE_JAVA_LIBRARIES=$(PRIVATE_JAVA_LIBRARIES);
+@echo PRIVATE_ALL_SHARED_LIBRARIES=$(PRIVATE_ALL_SHARED_LIBRARIES);
+@echo PRIVATE_ALL_STATIC_LIBRARIES=$(PRIVATE_ALL_STATIC_LIBRARIES);
+@echo PRIVATE_ALL_WHOLE_STATIC_LIBRARIES=$(PRIVATE_ALL_WHOLE_STATIC_LIBRARIES);
+@echo PRIVATE_ALL_OBJECTS=$(PRIVATE_ALL_OBJECTS);
+endef
+
+###########################################################
+## Commands for using sed to replace given variable values
+###########################################################
+
+define transform-variables
+@mkdir -p $(dir $@)
+@echo "Sed: $(if $(PRIVATE_MODULE),$(PRIVATE_MODULE),$@) <= $<"
+$(hide) sed $(foreach var,$(REPLACE_VARS),-e "s/{{$(var)}}/$(subst /,\/,$(PWD)/$($(var)))/g") $< >$@
+$(hide) if [ "$(suffix $@)" = ".sh" ]; then chmod a+rx $@; fi
+endef
+
+
+###########################################################
+## Commands for munging the dependency files GCC generates
+###########################################################
+
+define transform-d-to-p
+@cp $(@:%.o=%.d) $(@:%.o=%.P); \
+       sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
+               -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
+       rm -f $(@:%.o=%.d)
+endef
+
+###########################################################
+## Commands for running lex
+###########################################################
+
+define transform-l-to-cpp
+@mkdir -p $(dir $@)
+@echo "Lex: $(PRIVATE_MODULE) <= $<"
+$(hide) $(LEX) -o$@ $<
+endef
+
+###########################################################
+## Commands for running yacc
+##
+## Because the extension of c++ files can change, the
+## extension must be specified in $1.
+## E.g, "$(call transform-y-to-cpp,.cpp)"
+###########################################################
+
+define transform-y-to-cpp
+@mkdir -p $(dir $@)
+@echo "Yacc: $(PRIVATE_MODULE) <= $<"
+$(YACC) $(PRIVATE_YACCFLAGS) -o $@ $<
+touch $(@:$1=$(YACC_HEADER_SUFFIX))
+echo '#ifndef '$(@F:$1=_h) > $(@:$1=.h)
+echo '#define '$(@F:$1=_h) >> $(@:$1=.h)
+cat $(@:$1=$(YACC_HEADER_SUFFIX)) >> $(@:$1=.h)
+echo '#endif' >> $(@:$1=.h)
+rm -f $(@:$1=$(YACC_HEADER_SUFFIX))
+endef
+
+
+###########################################################
+## Commands for running aidl
+###########################################################
+
+define transform-aidl-to-java
+@mkdir -p $(dir $@)
+@echo "Aidl: $(PRIVATE_MODULE) <= $<"
+$(hide) $(AIDL) -d$(patsubst %.java,%.P,$@) $(PRIVATE_AIDL_FLAGS) $< $@
+endef
+#$(AIDL) $(PRIVATE_AIDL_FLAGS) $< - | indent -nut -br -npcs -l1000 > $@
+
+
+###########################################################
+## Commands for running java-event-log-tags.py
+###########################################################
+
+define transform-logtags-to-java
+@mkdir -p $(dir $@)
+@echo "logtags: $@ <= $<"
+$(hide) $(JAVATAGS) -o $@ $^
+endef
+
+
+###########################################################
+## Commands for running protoc to compile .proto into .java
+###########################################################
+
+define transform-proto-to-java
+@mkdir -p $(dir $@)
+@echo "Protoc: $@ <= $(PRIVATE_PROTO_SRC_FILES)"
+@rm -rf $(PRIVATE_PROTO_JAVA_OUTPUT_DIR)
+@mkdir -p $(PRIVATE_PROTO_JAVA_OUTPUT_DIR)
+$(hide) $(PROTOC) \
+       $(addprefix --proto_path=, $(PRIVATE_PROTO_INCLUDES)) \
+       $(PRIVATE_PROTO_JAVA_OUTPUT_OPTION)=$(PRIVATE_PROTO_JAVA_OUTPUT_DIR) \
+       $(PRIVATE_PROTOC_FLAGS) \
+       $(PRIVATE_PROTO_SRC_FILES)
+$(hide) touch $@
+endef
+
+######################################################################
+## Commands for running protoc to compile .proto into .pb.cc and .pb.h
+######################################################################
+define transform-proto-to-cc
+@mkdir -p $(dir $@)
+@echo "Protoc: $@ <= $<"
+$(hide) $(PROTOC) \
+       $(addprefix --proto_path=, $(PRIVATE_PROTO_INCLUDES)) \
+       $(PRIVATE_PROTOC_FLAGS) \
+       --cpp_out=$(PRIVATE_PROTO_CC_OUTPUT_DIR) $<
+endef
+
+
+###########################################################
+## Commands for running gcc to compile a C++ file
+###########################################################
+
+define transform-cpp-to-o
+@mkdir -p $(dir $@)
+@echo "target $(PRIVATE_ARM_MODE) C++: $(PRIVATE_MODULE) <= $<"
+$(hide) $(PRIVATE_CXX) \
+       $(foreach incdir, \
+           $(PRIVATE_C_INCLUDES) \
+           $(if $(PRIVATE_NO_DEFAULT_COMPILER_FLAGS),, \
+               $(PRIVATE_TARGET_PROJECT_INCLUDES) \
+               $(PRIVATE_TARGET_C_INCLUDES) \
+            ) \
+         , \
+           -I $(incdir) \
+        ) \
+       -c \
+       $(if $(PRIVATE_NO_DEFAULT_COMPILER_FLAGS),, \
+           $(PRIVATE_TARGET_GLOBAL_CFLAGS) \
+           $(PRIVATE_TARGET_GLOBAL_CPPFLAGS) \
+           $(PRIVATE_ARM_CFLAGS) \
+        ) \
+       -fno-rtti \
+       $(PRIVATE_CFLAGS) \
+       $(PRIVATE_CPPFLAGS) \
+       $(PRIVATE_DEBUG_CFLAGS) \
+       -MD -o $@ $<
+$(hide) $(transform-d-to-p)
+endef
+
+
+###########################################################
+## Commands for running gcc to compile a C file
+###########################################################
+
+# $(1): extra flags
+define transform-c-or-s-to-o-no-deps
+@mkdir -p $(dir $@)
+$(hide) $(PRIVATE_CC) \
+       $(foreach incdir, \
+           $(PRIVATE_C_INCLUDES) \
+           $(if $(PRIVATE_NO_DEFAULT_COMPILER_FLAGS),, \
+               $(PRIVATE_TARGET_PROJECT_INCLUDES) \
+               $(PRIVATE_TARGET_C_INCLUDES) \
+            ) \
+         , \
+           -I $(incdir) \
+        ) \
+       -c \
+       $(if $(PRIVATE_NO_DEFAULT_COMPILER_FLAGS),, \
+           $(PRIVATE_TARGET_GLOBAL_CFLAGS) \
+           $(PRIVATE_ARM_CFLAGS) \
+        ) \
+       $(PRIVATE_CFLAGS) \
+       $(1) \
+       $(PRIVATE_DEBUG_CFLAGS) \
+       -MD -o $@ $<
+endef
+
+define transform-c-to-o-no-deps
+@echo "target $(PRIVATE_ARM_MODE) C: $(PRIVATE_MODULE) <= $<"
+$(call transform-c-or-s-to-o-no-deps, )
+endef
+
+define transform-s-to-o-no-deps
+@echo "target asm: $(PRIVATE_MODULE) <= $<"
+$(call transform-c-or-s-to-o-no-deps, $(PRIVATE_ASFLAGS))
+endef
+
+define transform-c-to-o
+$(transform-c-to-o-no-deps)
+$(hide) $(transform-d-to-p)
+endef
+
+define transform-s-to-o
+$(transform-s-to-o-no-deps)
+$(hide) $(transform-d-to-p)
+endef
+
+###########################################################
+## Commands for running gcc to compile an Objective-C file
+## This should never happen for target builds but this
+## will error at build time.
+###########################################################
+
+define transform-m-to-o-no-deps
+@echo "target ObjC: $(PRIVATE_MODULE) <= $<"
+$(call transform-c-or-s-to-o-no-deps)
+endef
+
+define transform-m-to-o
+$(transform-m-to-o-no-deps)
+$(hide) $(transform-d-to-p)
+endef
+
+###########################################################
+## Commands for running gcc to compile a host C++ file
+###########################################################
+
+define transform-host-cpp-to-o
+@mkdir -p $(dir $@)
+@echo "host C++: $(PRIVATE_MODULE) <= $<"
+$(hide) $(PRIVATE_CXX) \
+       $(foreach incdir, \
+           $(PRIVATE_C_INCLUDES) \
+           $(if $(PRIVATE_NO_DEFAULT_COMPILER_FLAGS),, \
+               $(HOST_PROJECT_INCLUDES) \
+               $(HOST_C_INCLUDES) \
+            ) \
+         , \
+           -I $(incdir) \
+        ) \
+       -c \
+       $(if $(PRIVATE_NO_DEFAULT_COMPILER_FLAGS),, \
+           $(HOST_GLOBAL_CFLAGS) \
+           $(HOST_GLOBAL_CPPFLAGS) \
+        ) \
+       $(PRIVATE_CFLAGS) \
+       $(PRIVATE_CPPFLAGS) \
+       $(PRIVATE_DEBUG_CFLAGS) \
+       -MD -o $@ $<
+$(transform-d-to-p)
+endef
+
+
+###########################################################
+## Commands for running gcc to compile a host C file
+###########################################################
+
+# $(1): extra flags
+define transform-host-c-or-s-to-o-no-deps
+@mkdir -p $(dir $@)
+$(hide) $(PRIVATE_CC) \
+       $(foreach incdir, \
+           $(PRIVATE_C_INCLUDES) \
+           $(if $(PRIVATE_NO_DEFAULT_COMPILER_FLAGS),, \
+               $(HOST_PROJECT_INCLUDES) \
+               $(HOST_C_INCLUDES) \
+            ) \
+         , \
+           -I $(incdir) \
+        ) \
+       -c \
+       $(if $(PRIVATE_NO_DEFAULT_COMPILER_FLAGS),, \
+           $(HOST_GLOBAL_CFLAGS) \
+        ) \
+       $(PRIVATE_CFLAGS) \
+       $(1) \
+       $(PRIVATE_DEBUG_CFLAGS) \
+       -MD -o $@ $<
+endef
+
+define transform-host-c-to-o-no-deps
+@echo "host C: $(PRIVATE_MODULE) <= $<"
+$(call transform-host-c-or-s-to-o-no-deps, )
+endef
+
+define transform-host-s-to-o-no-deps
+@echo "host asm: $(PRIVATE_MODULE) <= $<"
+$(call transform-host-c-or-s-to-o-no-deps, $(PRIVATE_ASFLAGS))
+endef
+
+define transform-host-c-to-o
+$(transform-host-c-to-o-no-deps)
+$(transform-d-to-p)
+endef
+
+define transform-host-s-to-o
+$(transform-host-s-to-o-no-deps)
+$(transform-d-to-p)
+endef
+
+###########################################################
+## Commands for running gcc to compile a host Objective-C file
+###########################################################
+
+define transform-host-m-to-o-no-deps
+@echo "host ObjC: $(PRIVATE_MODULE) <= $<"
+$(call transform-host-c-or-s-to-o-no-deps)
+endef
+
+define tranform-host-m-to-o
+$(transform-host-m-to-o-no-deps)
+$(transform-d-to-p)
+endef
+
+###########################################################
+## Commands for running ar
+###########################################################
+
+define extract-and-include-target-whole-static-libs
+$(foreach lib,$(PRIVATE_ALL_WHOLE_STATIC_LIBRARIES), \
+       $(hide) echo "preparing StaticLib: $(PRIVATE_MODULE) [including $(lib)]"; \
+       ldir=$(PRIVATE_INTERMEDIATES_DIR)/WHOLE/$(basename $(notdir $(lib)))_objs;\
+       rm -rf $$ldir; \
+       mkdir -p $$ldir; \
+       filelist=; \
+       for f in `$(TARGET_AR) t $(lib)`; do \
+           $(TARGET_AR) p $(lib) $$f > $$ldir/$$f; \
+           filelist="$$filelist $$ldir/$$f"; \
+       done ; \
+       $(TARGET_AR) $(TARGET_GLOBAL_ARFLAGS) $(PRIVATE_ARFLAGS) $@ $$filelist;\
+)
+endef
+
+# Explicitly delete the archive first so that ar doesn't
+# try to add to an existing archive.
+define transform-o-to-static-lib
+@mkdir -p $(dir $@)
+@rm -f $@
+$(extract-and-include-target-whole-static-libs)
+@echo "target StaticLib: $(PRIVATE_MODULE) ($@)"
+$(hide) echo $(filter %.o, $^) | \
+    xargs $(TARGET_AR) $(TARGET_GLOBAL_ARFLAGS) $(PRIVATE_ARFLAGS) $@
+endef
+
+###########################################################
+## Commands for running host ar
+###########################################################
+
+define extract-and-include-host-whole-static-libs
+$(foreach lib,$(PRIVATE_ALL_WHOLE_STATIC_LIBRARIES), \
+       @echo "preparing StaticLib: $(PRIVATE_MODULE) [including $(lib)]"; \
+       ldir=$(PRIVATE_INTERMEDIATES_DIR)/WHOLE/$(basename $(notdir $(lib)))_objs;\
+       rm -rf $$ldir; \
+       mkdir -p $$ldir; \
+       filelist=; \
+       for f in `$(HOST_AR) t $(lib) | grep '\.o$$'`; do \
+           $(HOST_AR) p $(lib) $$f > $$ldir/$$f; \
+           filelist="$$filelist $$ldir/$$f"; \
+       done ; \
+       $(HOST_AR) $(HOST_GLOBAL_ARFLAGS) $(PRIVATE_ARFLAGS) $@ $$filelist;\
+)
+endef
+
+# Explicitly delete the archive first so that ar doesn't
+# try to add to an existing archive.
+define transform-host-o-to-static-lib
+@mkdir -p $(dir $@)
+@rm -f $@
+$(extract-and-include-host-whole-static-libs)
+@echo "host StaticLib: $(PRIVATE_MODULE) ($@)"
+echo $(filter %.o, $^) | \
+       xargs $(HOST_AR) $(HOST_GLOBAL_ARFLAGS) $(PRIVATE_ARFLAGS) $@
+endef
+
+
+###########################################################
+## Commands for running gcc to link a shared library or package
+###########################################################
+
+# ld just seems to be so finicky with command order that we allow
+# it to be overriden en-masse see combo/linux-arm.make for an example.
+ifneq ($(HOST_CUSTOM_LD_COMMAND),true)
+define transform-host-o-to-shared-lib-inner
+$(PRIVATE_CXX) \
+       -Wl,-rpath-link=$(TARGET_OUT_INTERMEDIATE_LIBRARIES) \
+       -Wl,-rpath,\$$ORIGIN/../lib \
+       -shared -Wl,-soname,$(notdir $@) \
+       $(PRIVATE_LDFLAGS) \
+       $(HOST_GLOBAL_LD_DIRS) \
+       $(if $(PRIVATE_NO_DEFAULT_COMPILER_FLAGS),, \
+          $(HOST_GLOBAL_LDFLAGS) \
+       ) \
+       $(PRIVATE_ALL_OBJECTS) \
+       -Wl,--whole-archive \
+       $(call normalize-host-libraries,$(PRIVATE_ALL_WHOLE_STATIC_LIBRARIES)) \
+       -Wl,--no-whole-archive \
+       $(call normalize-host-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
+       $(call normalize-host-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
+       -o $@ \
+       $(PRIVATE_LDLIBS)
+endef
+endif
+
+define transform-host-o-to-shared-lib
+@mkdir -p $(dir $@)
+@echo "host SharedLib: $(PRIVATE_MODULE) ($@)"
+$(hide) $(transform-host-o-to-shared-lib-inner)
+endef
+
+define transform-host-o-to-package
+@mkdir -p $(dir $@)
+@echo "host Package: $(PRIVATE_MODULE) ($@)"
+$(hide) $(transform-host-o-to-shared-lib-inner)
+endef
+
+
+###########################################################
+## Commands for running gcc to link a shared library or package
+###########################################################
+
+#echo >$@.vers "{"; \
+#echo >>$@.vers " global:"; \
+#$(BUILD_SYSTEM)/filter_symbols.sh $(TARGET_NM) "  " ";" $(filter %.o,$^) | sort -u >>$@.vers; \
+#echo >>$@.vers " local:"; \
+#echo >>$@.vers "  *;"; \
+#echo >>$@.vers "};"; \
+
+#      -Wl,--version-script=$@.vers \
+
+# ld just seems to be so finicky with command order that we allow
+# it to be overriden en-masse see combo/linux-arm.make for an example.
+ifneq ($(TARGET_CUSTOM_LD_COMMAND),true)
+define transform-o-to-shared-lib-inner
+$(PRIVATE_CXX) \
+       $(PRIVATE_TARGET_GLOBAL_LDFLAGS) \
+       -Wl,-rpath-link=$(TARGET_OUT_INTERMEDIATE_LIBRARIES) \
+       -Wl,-rpath,\$$ORIGIN/../lib \
+       -shared -Wl,-soname,$(notdir $@) \
+       $(PRIVATE_LDFLAGS) \
+       $(PRIVATE_TARGET_GLOBAL_LD_DIRS) \
+       $(PRIVATE_ALL_OBJECTS) \
+       -Wl,--whole-archive \
+       $(call normalize-host-libraries,$(PRIVATE_ALL_WHOLE_STATIC_LIBRARIES)) \
+       -Wl,--no-whole-archive \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
+       -o $@ \
+       $(PRIVATE_LDLIBS)
+endef
+endif
+
+define transform-o-to-shared-lib
+@mkdir -p $(dir $@)
+@echo "target SharedLib: $(PRIVATE_MODULE) ($@)"
+$(hide) $(transform-o-to-shared-lib-inner)
+endef
+
+define transform-o-to-package
+@mkdir -p $(dir $@)
+@echo "target Package: $(PRIVATE_MODULE) ($@)"
+$(hide) $(transform-o-to-shared-lib-inner)
+endef
+
+
+###########################################################
+## Commands for filtering a target executable or library
+###########################################################
+
+define transform-to-stripped
+@mkdir -p $(dir $@)
+@echo "target Strip: $(PRIVATE_MODULE) ($@)"
+$(hide) $(TARGET_STRIP_COMMAND)
+endef
+
+define transform-to-prelinked
+@mkdir -p $(dir $@)
+@echo "target Prelink: $(PRIVATE_MODULE) ($@)"
+$(hide) $(APRIORI) \
+               --prelinkmap $(TARGET_PRELINKER_MAP) \
+               --locals-only \
+               --quiet \
+               $< \
+               --output $@
+endef
+
+
+###########################################################
+## Commands for running gcc to link an executable
+###########################################################
+
+ifneq ($(TARGET_CUSTOM_LD_COMMAND),true)
+define transform-o-to-executable-inner
+$(PRIVATE_CXX) \
+       $(TARGET_GLOBAL_LDFLAGS) \
+       -Wl,-rpath-link=$(TARGET_OUT_INTERMEDIATE_LIBRARIES) \
+       $(TARGET_GLOBAL_LD_DIRS) \
+       -Wl,-rpath-link=$(TARGET_OUT_INTERMEDIATE_LIBRARIES) \
+       -Wl,-rpath,\$$ORIGIN/../lib \
+       $(PRIVATE_LDFLAGS) \
+       $(TARGET_GLOBAL_LD_DIRS) \
+       $(PRIVATE_ALL_OBJECTS) \
+       -Wl,--whole-archive \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_WHOLE_STATIC_LIBRARIES)) \
+       -Wl,--no-whole-archive \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
+       $(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
+       -o $@ \
+       $(PRIVATE_LDLIBS)
+endef
+endif
+
+define transform-o-to-executable
+@mkdir -p $(dir $@)
+@echo "target Executable: $(PRIVATE_MODULE) ($@)"
+$(hide) $(transform-o-to-executable-inner)
+endef
+
+
+###########################################################
+## Commands for running gcc to link a statically linked
+## executable.  In practice, we only use this on arm, so
+## the other platforms don't have the
+## transform-o-to-static-executable defined
+###########################################################
+
+ifneq ($(TARGET_CUSTOM_LD_COMMAND),true)
+define transform-o-to-static-executable-inner
+endef
+endif
+
+define transform-o-to-static-executable
+@mkdir -p $(dir $@)
+@echo "target StaticExecutable: $(PRIVATE_MODULE) ($@)"
+$(hide) $(transform-o-to-static-executable-inner)
+endef
+
+
+###########################################################
+## Commands for running gcc to link a host executable
+###########################################################
+
+ifneq ($(HOST_CUSTOM_LD_COMMAND),true)
+define transform-host-o-to-executable-inner
+$(PRIVATE_CXX) \
+       -Wl,-rpath-link=$(TARGET_OUT_INTERMEDIATE_LIBRARIES) \
+       -Wl,-rpath,\$$ORIGIN/../lib \
+       $(HOST_GLOBAL_LD_DIRS) \
+       $(PRIVATE_LDFLAGS) \
+       $(if $(PRIVATE_NO_DEFAULT_COMPILER_FLAGS),, \
+               $(HOST_GLOBAL_LDFLAGS) \
+       ) \
+       $(PRIVATE_ALL_OBJECTS) \
+       -Wl,--whole-archive \
+       $(call normalize-host-libraries,$(PRIVATE_ALL_WHOLE_STATIC_LIBRARIES)) \
+       -Wl,--no-whole-archive \
+       $(call normalize-host-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
+       $(call normalize-host-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
+       -o $@ \
+       $(PRIVATE_LDLIBS)
+endef
+endif
+
+define transform-host-o-to-executable
+@mkdir -p $(dir $@)
+@echo "host Executable: $(PRIVATE_MODULE) ($@)"
+$(hide) $(transform-host-o-to-executable-inner)
+endef
+
+
+###########################################################
+## Commands for running javac to make .class files
+###########################################################
+
+#@echo "Source intermediates dir: $(PRIVATE_SOURCE_INTERMEDIATES_DIR)"
+#@echo "Source intermediates: $$(find $(PRIVATE_SOURCE_INTERMEDIATES_DIR) -name '*.java')"
+
+# TODO: Right now we generate the asset resources twice, first as part
+# of generating the Java classes, then at the end when packaging the final
+# assets.  This should be changed to do one of two things: (1) Don't generate
+# any resource files the first time, only create classes during that stage;
+# or (2) Don't use the -c flag with the second stage, instead taking the
+# resource files from the first stage as additional input.  My original intent
+# was to use approach (2), but this requires a little more work in the tool.
+# Maybe we should just use approach (1).
+
+# This rule creates the R.java and Manifest.java files, both of which
+# are PRODUCT-neutral.  Don't pass PRODUCT_AAPT_CONFIG to this invocation.
+define create-resource-java-files
+@mkdir -p $(PRIVATE_SOURCE_INTERMEDIATES_DIR)
+@mkdir -p $(dir $(PRIVATE_RESOURCE_PUBLICS_OUTPUT))
+$(hide) $(AAPT) package $(PRIVATE_AAPT_FLAGS) -m \
+    $(eval # PRODUCT_AAPT_CONFIG is intentionally missing-- see comment.) \
+    $(addprefix -J , $(PRIVATE_SOURCE_INTERMEDIATES_DIR)) \
+    $(addprefix -M , $(PRIVATE_ANDROID_MANIFEST)) \
+    $(addprefix -P , $(PRIVATE_RESOURCE_PUBLICS_OUTPUT)) \
+    $(addprefix -S , $(PRIVATE_RESOURCE_DIR)) \
+    $(addprefix -A , $(PRIVATE_ASSET_DIR)) \
+    $(addprefix -I , $(PRIVATE_AAPT_INCLUDES)) \
+    $(addprefix -G , $(PRIVATE_PROGUARD_OPTIONS_FILE)) \
+    $(addprefix --min-sdk-version , $(DEFAULT_APP_TARGET_SDK)) \
+    $(addprefix --target-sdk-version , $(DEFAULT_APP_TARGET_SDK)) \
+    $(if $(filter --version-code,$(PRIVATE_AAPT_FLAGS)),,$(addprefix --version-code , $(PLATFORM_SDK_VERSION))) \
+    $(if $(filter --version-name,$(PRIVATE_AAPT_FLAGS)),,$(addprefix --version-name , $(PLATFORM_VERSION))) \
+    $(addprefix --rename-manifest-package , $(PRIVATE_MANIFEST_PACKAGE_NAME)) \
+    $(addprefix --rename-instrumentation-target-package , $(PRIVATE_MANIFEST_INSTRUMENTATION_FOR))
+endef
+
+ifeq ($(HOST_OS),windows)
+xlint_unchecked :=
+else
+xlint_unchecked := -Xlint:unchecked
+endif
+
+# emit-line, <word list>, <output file>
+define emit-line
+   $(if $(1),echo -n '$(strip $(1)) ' >> $(2))
+endef
+
+# dump-words-to-file, <word list>, <output file>
+define dump-words-to-file
+        @rm -f $(2)
+        @$(call emit-line,$(wordlist 1,200,$(1)),$(2))
+        @$(call emit-line,$(wordlist 201,400,$(1)),$(2))
+        @$(call emit-line,$(wordlist 401,600,$(1)),$(2))
+        @$(call emit-line,$(wordlist 601,800,$(1)),$(2))
+        @$(call emit-line,$(wordlist 801,1000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 1001,1200,$(1)),$(2))
+        @$(call emit-line,$(wordlist 1201,1400,$(1)),$(2))
+        @$(call emit-line,$(wordlist 1401,1600,$(1)),$(2))
+        @$(call emit-line,$(wordlist 1601,1800,$(1)),$(2))
+        @$(call emit-line,$(wordlist 1801,2000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 2001,2200,$(1)),$(2))
+        @$(call emit-line,$(wordlist 2201,2400,$(1)),$(2))
+        @$(call emit-line,$(wordlist 2401,2600,$(1)),$(2))
+        @$(call emit-line,$(wordlist 2601,2800,$(1)),$(2))
+        @$(call emit-line,$(wordlist 2801,3000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 3001,3200,$(1)),$(2))
+        @$(call emit-line,$(wordlist 3201,3400,$(1)),$(2))
+        @$(call emit-line,$(wordlist 3401,3600,$(1)),$(2))
+        @$(call emit-line,$(wordlist 3601,3800,$(1)),$(2))
+        @$(call emit-line,$(wordlist 3801,4000,$(1)),$(2))
+        @$(if $(wordlist 4001,4002,$(1)),$(error Too many words ($(words $(1)))))
+endef
+
+# For a list of jar files, unzip them to a specified directory,
+# but make sure that no META-INF files come along for the ride.
+#
+# $(1): files to unzip
+# $(2): destination directory
+define unzip-jar-files
+  $(hide) for f in $(1); \
+  do \
+    if [ ! -f $$f ]; then \
+      echo Missing file $$f; \
+      exit 1; \
+    fi; \
+    unzip -qo $$f -d $(2); \
+    (cd $(2) && rm -rf META-INF); \
+  done
+endef
+
+# below we write the list of java files to java-source-list to avoid argument
+# list length problems with Cygwin we filter out duplicate java file names
+# because eclipse's compiler doesn't like them.
+define transform-java-to-classes.jar
+@echo "target Java: $(PRIVATE_MODULE) ($(PRIVATE_CLASS_INTERMEDIATES_DIR))"
+$(hide) rm -f $@
+$(hide) rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR)
+$(hide) mkdir -p $(PRIVATE_CLASS_INTERMEDIATES_DIR)
+$(call unzip-jar-files,$(PRIVATE_STATIC_JAVA_LIBRARIES), \
+    $(PRIVATE_CLASS_INTERMEDIATES_DIR))
+$(call dump-words-to-file,$(PRIVATE_JAVA_SOURCES),$(dir $(PRIVATE_CLASS_INTERMEDIATES_DIR))/java-source-list)
+$(hide) if [ -d "$(PRIVATE_SOURCE_INTERMEDIATES_DIR)" ]; then \
+           find $(PRIVATE_SOURCE_INTERMEDIATES_DIR) -name '*.java' >> $(dir $(PRIVATE_CLASS_INTERMEDIATES_DIR))/java-source-list; \
+fi
+$(hide) tr ' ' '\n' < $(dir $(PRIVATE_CLASS_INTERMEDIATES_DIR))/java-source-list \
+    | sort -u > $(dir $(PRIVATE_CLASS_INTERMEDIATES_DIR))/java-source-list-uniq
+$(hide) $(TARGET_JAVAC) -encoding ascii $(PRIVATE_BOOTCLASSPATH) \
+    $(addprefix -classpath ,$(strip \
+        $(call normalize-path-list,$(PRIVATE_ALL_JAVA_LIBRARIES)))) \
+    $(PRIVATE_JAVACFLAGS) $(strip $(PRIVATE_JAVAC_DEBUG_FLAGS)) \
+       $(if $(findstring true,$(LOCAL_WARNINGS_ENABLE)),$(xlint_unchecked),) \
+    -extdirs "" -d $(PRIVATE_CLASS_INTERMEDIATES_DIR) \
+    \@$(dir $(PRIVATE_CLASS_INTERMEDIATES_DIR))/java-source-list-uniq \
+    || ( rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR) ; exit 41 )
+$(hide) rm -f $(dir $(PRIVATE_CLASS_INTERMEDIATES_DIR))/java-source-list
+$(hide) rm -f $(dir $(PRIVATE_CLASS_INTERMEDIATES_DIR))/java-source-list-uniq
+$(hide) mkdir -p $(dir $@)
+$(hide) jar $(if $(strip $(PRIVATE_JAR_MANIFEST)),-cfm,-cf) \
+    $@ $(PRIVATE_JAR_MANIFEST) -C $(PRIVATE_CLASS_INTERMEDIATES_DIR) .
+$(hide) rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR)
+endef
+
+define transform-classes.jar-to-emma
+$(hide) java -classpath $(EMMA_JAR) emma instr -outmode fullcopy -outfile \
+    $(PRIVATE_EMMA_COVERAGE_FILE) -ip $< -d $(PRIVATE_EMMA_INTERMEDIATES_DIR) \
+    $(addprefix -ix , $(PRIVATE_EMMA_COVERAGE_FILTER))
+endef
+
+#TODO: use a smaller -Xmx value for most libraries;
+#      only core.jar and framework.jar need a heap this big.
+# Avoid the memory arguments on Windows, dx fails to load for some reason with them.
+define transform-classes.jar-to-dex
+@echo "target Dex: $(PRIVATE_MODULE)"
+@mkdir -p $(dir $@)
+$(hide) $(DX) \
+    $(if $(findstring windows,$(HOST_OS)),,-JXms16M -JXmx1536M) \
+    --dex --output=$@ \
+    $(if $(NO_OPTIMIZE_DX), \
+        --no-optimize) \
+    $(if $(GENERATE_DEX_DEBUG), \
+           --debug --verbose \
+           --dump-to=$(@:.dex=.lst) \
+           --dump-width=1000) \
+    $(PRIVATE_DX_FLAGS) \
+    $<
+endef
+
+# Create a mostly-empty .jar file that we'll add to later.
+# The MacOS jar tool doesn't like creating empty jar files,
+# so we need to give it something.
+define create-empty-package
+@mkdir -p $(dir $@)
+$(hide) touch $(dir $@)/dummy
+$(hide) (cd $(dir $@) && jar cf $(notdir $@) dummy)
+$(hide) zip -qd $@ dummy
+$(hide) rm $(dir $@)/dummy
+endef
+
+#TODO: we kinda want to build different asset packages for
+#      different configurations, then combine them later (or something).
+#      Per-locale, etc.
+#      A list of dynamic and static parameters;  build layers for
+#      dynamic params that lay over the static ones.
+#TODO: update the manifest to point to the package file
+#Note that the version numbers are given to aapt as simple default
+#values; applications can override these by explicitly stating
+#them in their manifest.
+define add-assets-to-package
+$(hide) $(AAPT) package -u $(PRIVATE_AAPT_FLAGS) \
+    $(addprefix -c , $(PRODUCT_AAPT_CONFIG)) \
+    $(addprefix -M , $(PRIVATE_ANDROID_MANIFEST)) \
+    $(addprefix -S , $(PRIVATE_RESOURCE_DIR)) \
+    $(addprefix -A , $(PRIVATE_ASSET_DIR)) \
+    $(addprefix -I , $(PRIVATE_AAPT_INCLUDES)) \
+    $(addprefix --min-sdk-version , $(DEFAULT_APP_TARGET_SDK)) \
+    $(addprefix --target-sdk-version , $(DEFAULT_APP_TARGET_SDK)) \
+    $(addprefix --product , $(TARGET_AAPT_CHARACTERISTICS)) \
+    $(if $(filter --version-code,$(PRIVATE_AAPT_FLAGS)),,$(addprefix --version-code , $(PLATFORM_SDK_VERSION))) \
+    $(if $(filter --version-name,$(PRIVATE_AAPT_FLAGS)),,$(addprefix --version-name , $(PLATFORM_VERSION))) \
+    $(addprefix --rename-manifest-package , $(PRIVATE_MANIFEST_PACKAGE_NAME)) \
+    $(addprefix --rename-instrumentation-target-package , $(PRIVATE_MANIFEST_INSTRUMENTATION_FOR)) \
+    -F $@
+endef
+
+define add-jni-shared-libs-to-package
+$(hide) rm -rf $(dir $@)lib
+$(hide) mkdir -p $(dir $@)lib/$(TARGET_CPU_ABI)
+$(hide) cp $(PRIVATE_JNI_SHARED_LIBRARIES) $(dir $@)lib/$(TARGET_CPU_ABI)
+$(hide) (cd $(dir $@) && zip -r $(notdir $@) lib)
+$(hide) rm -rf $(dir $@)lib
+endef
+
+#TODO: update the manifest to point to the dex file
+define add-dex-to-package
+$(if $(filter classes.dex,$(notdir $(PRIVATE_DEX_FILE))),\
+$(hide) $(AAPT) add -k $@ $(PRIVATE_DEX_FILE),\
+$(eval _adtp_classes.dex := $(dir $(PRIVATE_DEX_FILE))/classes.dex)\
+$(hide) cp $(PRIVATE_DEX_FILE) $(_adtp_classes.dex) && \
+$(AAPT) add -k $@ $(_adtp_classes.dex) && \
+rm -f $(_adtp_classes.dex))
+endef
+
+define add-java-resources-to-package
+$(hide) jar uf $@ $(PRIVATE_EXTRA_JAR_ARGS)
+endef
+
+# Sign a package using the specified key/cert.
+#
+define sign-package
+$(hide) mv $@ $@.unsigned
+$(hide) java -jar $(SIGNAPK_JAR) \
+       $(PRIVATE_CERTIFICATE) $(PRIVATE_PRIVATE_KEY) $@.unsigned $@.signed
+$(hide) mv $@.signed $@
+endef
+
+# Align STORED entries of a package on 4-byte boundaries
+# to make them easier to mmap.
+#
+define align-package
+$(hide) mv $@ $@.unaligned
+$(hide) $(ZIPALIGN) -f 4 $@.unaligned $@.aligned
+$(hide) mv $@.aligned $@
+endef
+
+define install-dex-debug
+$(hide) if [ -f "$(PRIVATE_INTERMEDIATES_DIR)/classes.dex" ]; then \
+           mkdir -p $(TOP)/dalvik/DEBUG-FILES; \
+           $(ACP) $(PRIVATE_INTERMEDIATES_DIR)/classes.dex \
+               $(TOP)/dalvik/DEBUG-FILES/$(PRIVATE_MODULE).dex; \
+       fi
+$(hide) if [ -f "$(PRIVATE_INTERMEDIATES_DIR)/classes.lst" ]; then \
+           mkdir -p $(TOP)/dalvik/DEBUG-FILES; \
+           $(ACP) $(PRIVATE_INTERMEDIATES_DIR)/classes.lst \
+               $(TOP)/dalvik/DEBUG-FILES/$(PRIVATE_MODULE).lst; \
+       fi
+endef
+
+# TODO(joeo): If we can ever upgrade to post 3.81 make and get the
+# new prebuilt rules to work, we should change this to copy the
+# resources to the out directory and then copy the resources.
+
+# Note: not using aapt tool for this because we aren't making
+# an android package for the host.
+define transform-host-java-to-package
+@echo "host Java: $(PRIVATE_MODULE) ($(PRIVATE_CLASS_INTERMEDIATES_DIR))"
+@rm -f $@
+@rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR)
+@mkdir -p $(dir $@)
+@mkdir -p $(PRIVATE_CLASS_INTERMEDIATES_DIR)
+$(call unzip-jar-files,$(PRIVATE_STATIC_JAVA_LIBRARIES), \
+    $(PRIVATE_CLASS_INTERMEDIATES_DIR))
+$(call dump-words-to-file,$(sort\
+       $(PRIVATE_JAVA_SOURCES)),\
+       $(PRIVATE_INTERMEDIATES_DIR)/java-source-list-uniq)
+$(hide) $(HOST_JAVAC) -encoding ascii -g \
+       $(PRIVATE_JAVACFLAGS) $(xlint_unchecked) \
+       $(addprefix -classpath ,$(strip \
+               $(call normalize-path-list,$(PRIVATE_ALL_JAVA_LIBRARIES)))) \
+       -extdirs "" -d $(PRIVATE_CLASS_INTERMEDIATES_DIR)\
+        \@$(PRIVATE_INTERMEDIATES_DIR)/java-source-list-uniq || \
+       ( rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR) ; exit 41 )
+$(hide) rm -f $(PRIVATE_INTERMEDIATES_DIR)/java-source-list
+$(hide) rm -f $(PRIVATE_INTERMEDIATES_DIR)/java-source-list-uniq
+$(hide) jar $(if $(strip $(PRIVATE_JAR_MANIFEST)),-cfm,-cf) \
+    $@ $(PRIVATE_JAR_MANIFEST) $(PRIVATE_EXTRA_JAR_ARGS) \
+    -C $(PRIVATE_CLASS_INTERMEDIATES_DIR) .
+endef
+
+###########################################################
+## Obfuscate a jar file
+###########################################################
+
+# PRIVATE_KEEP_FILE is a file containing a list of classes
+# PRIVATE_INTERMEDIATES_DIR is a directory we can use for temporary files
+# The module using this must depend on
+#        $(HOST_OUT_JAVA_LIBRARIES)/proguard-4.0.1.jar
+define obfuscate-jar
+@echo "Obfuscate jar: $(notdir $@) ($@)"
+@mkdir -p $(dir $@)
+@rm -f $@
+@mkdir -p $(PRIVATE_INTERMEDIATES_DIR)
+$(hide) sed -e 's/^/-keep class /' < $(PRIVATE_KEEP_FILE) > \
+               $(PRIVATE_INTERMEDIATES_DIR)/keep.pro
+$(hide) java -Xmx512M -jar $(HOST_OUT_JAVA_LIBRARIES)/proguard-4.0.1.jar \
+               -injars $< \
+               -outjars $@ \
+               -target 1.5 \
+               -dontnote -dontwarn \
+               -printmapping $(PRIVATE_INTERMEDIATES_DIR)/out.map \
+               -forceprocessing \
+               -renamesourcefileattribute SourceFile \
+               -keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod \
+               -repackageclasses \
+               -keepclassmembers "class * { public protected *; }" \
+               @$(PRIVATE_INTERMEDIATES_DIR)/keep.pro
+endef
+
+###########################################################
+## Commands for copying files
+###########################################################
+
+# Define a rule to copy a header.  Used via $(eval) by copy_headers.make.
+# $(1): source header
+# $(2): destination header
+define copy-one-header
+$(2): $(1)
+       @echo "Header: $$@"
+       $$(copy-file-to-new-target-with-cp)
+endef
+
+# Define a rule to copy a file.  For use via $(eval).
+# $(1): source file
+# $(2): destination file
+define copy-one-file
+$(2): $(1) | $(ACP)
+       @echo "Copy: $$@"
+       $$(copy-file-to-target)
+endef
+
+# The -t option to acp and the -p option to cp is
+# required for OSX.  OSX has a ridiculous restriction
+# where it's an error for a .a file's modification time
+# to disagree with an internal timestamp, and this
+# macro is used to install .a files (among other things).
+
+# Copy a single file from one place to another,
+# preserving permissions and overwriting any existing
+# file.
+define copy-file-to-target
+@mkdir -p $(dir $@)
+$(hide) $(ACP) -fpt $< $@
+endef
+
+# The same as copy-file-to-target, but use the local
+# cp command instead of acp.
+define copy-file-to-target-with-cp
+@mkdir -p $(dir $@)
+$(hide) cp -fp $< $@
+endef
+
+# The same as copy-file-to-target, but use the zipalign tool to do so.
+define copy-file-to-target-with-zipalign
+@mkdir -p $(dir $@)
+$(hide) $(ZIPALIGN) -f 4 $< $@
+endef
+
+# The same as copy-file-to-target, but strip out "# comment"-style
+# comments (for config files and such).
+define copy-file-to-target-strip-comments
+@mkdir -p $(dir $@)
+$(hide) sed -e 's/#.*$$//' -e 's/[ \t]*$$//' -e '/^$$/d' < $< > $@
+endef
+
+# The same as copy-file-to-target, but don't preserve
+# the old modification time.
+define copy-file-to-new-target
+@mkdir -p $(dir $@)
+$(hide) $(ACP) -fp $< $@
+endef
+
+# The same as copy-file-to-new-target, but use the local
+# cp command instead of acp.
+define copy-file-to-new-target-with-cp
+@mkdir -p $(dir $@)
+$(hide) cp -f $< $@
+endef
+
+# Copy a prebuilt file to a target location.
+define transform-prebuilt-to-target
+@echo "$(if $(PRIVATE_IS_HOST_MODULE),host,target) Prebuilt: $(PRIVATE_MODULE) ($@)"
+$(copy-file-to-target)
+endef
+
+# Copy a prebuilt file to a target location, using zipalign on it.
+define transform-prebuilt-to-target-with-zipalign
+@echo "$(if $(PRIVATE_IS_HOST_MODULE),host,target) Prebuilt APK: $(PRIVATE_MODULE) ($@)"
+$(copy-file-to-target-with-zipalign)
+endef
+
+# Copy a prebuilt file to a target location, stripping "# comment" comments.
+define transform-prebuilt-to-target-strip-comments
+@echo "$(if $(PRIVATE_IS_HOST_MODULE),host,target) Prebuilt: $(PRIVATE_MODULE) ($@)"
+$(copy-file-to-target-strip-comments)
+endef
+
+###########################################################
+## On some platforms (MacOS), after copying a static
+## library, ranlib must be run to update an internal
+## timestamp!?!?!
+###########################################################
+
+ifeq ($(HOST_RUN_RANLIB_AFTER_COPYING),true)
+define transform-host-ranlib-copy-hack
+    $(hide) ranlib $@ || true
+endef
+else
+define transform-host-ranlib-copy-hack
+true
+endef
+endif
+
+ifeq ($(TARGET_RUN_RANLIB_AFTER_COPYING),true)
+define transform-ranlib-copy-hack
+    $(hide) ranlib $@
+endef
+else
+define transform-ranlib-copy-hack
+true
+endef
+endif
+
+
+###########################################################
+## Commands to call Proguard
+###########################################################
+
+# Command to copy the file with acp, if proguard is disabled.
+define proguard-disabled-commands
+@echo Copying: $@
+$(hide) $(ACP) $< $@
+endef
+
+# Command to call Proguard
+# $(1): extra flags for instrumentation.
+define proguard-enabled-commands
+@echo Proguard: $@
+$(hide) $(PROGUARD) -injars $< -outjars $@ $(PRIVATE_PROGUARD_FLAGS) $(1)
+endef
+
+# Figure out the proguard dictionary file of the module that is instrumentationed for.
+define get-instrumentation-proguard-flags
+$(if $(PRIVATE_INSTRUMENTATION_FOR),$(if $(ALL_MODULES.$(PRIVATE_INSTRUMENTATION_FOR).PROGUARD_ENABLED),-applymapping $(call intermediates-dir-for,APPS,$(PRIVATE_INSTRUMENTATION_FOR),,COMMON)/proguard_dictionary))
+endef
+
+define transform-jar-to-proguard
+$(eval _instrumentation_proguard_flags:=$(call get-instrumentation-proguard-flags))
+$(eval _enable_proguard:=$(PRIVATE_PROGUARD_ENABLED)$(_instrumentation_proguard_flags))
+$(if $(_enable_proguard),$(call proguard-enabled-commands,$(_instrumentation_proguard_flags)),$(call proguard-disabled-commands))
+$(eval _instrumentation_proguard_flags:=)
+$(eval _enable_proguard:=)
+endef
+
+
+###########################################################
+## Stuff source generated from one-off tools
+###########################################################
+
+define transform-generated-source
+@echo "target Generated: $(PRIVATE_MODULE) <= $<"
+@mkdir -p $(dir $@)
+$(hide) $(PRIVATE_CUSTOM_TOOL)
+endef
+
+
+###########################################################
+## Assertions about attributes of the target
+###########################################################
+
+# $(1): The file to check
+ifndef get-file-size
+$(error HOST_OS must define get-file-size)
+endif
+
+# Convert a partition data size (eg, as reported in /proc/mtd) to the
+# size of the image used to flash that partition (which includes a
+# spare area for each page).
+# $(1): the partition data size
+define image-size-from-data-size
+$(shell echo $$(($(1) / $(BOARD_NAND_PAGE_SIZE) * \
+  ($(BOARD_NAND_PAGE_SIZE)+$(BOARD_NAND_SPARE_SIZE)))))
+endef
+
+# $(1): The file(s) to check (often $@)
+# $(2): The maximum total image size, in decimal bytes
+# $(3): the type of filesystem "yaffs" or "raw"
+#
+# If $(2) is empty, evaluates to "true"
+#
+# Reserve bad blocks.  Make sure that MAX(1% of partition size, 2 blocks)
+# is left over after the image has been flashed.  Round the 1% up to the
+# next whole flash block size.
+define assert-max-file-size
+$(if $(2), \
+  size=$$(for i in $(1); do $(call get-file-size,$$i); echo +; done; echo 0); \
+  total=$$(( $$( echo "$$size" ) )); \
+  printname=$$(echo -n "$(1)" | tr " " +); \
+  echo "$$printname total size is $$total"; \
+  img_blocksize=$(call image-size-from-data-size,$(BOARD_FLASH_BLOCK_SIZE)); \
+  if [ "$(3)" == "yaffs" ]; then \
+    reservedblocks=8; \
+  else \
+    reservedblocks=0; \
+  fi; \
+  twoblocks=$$((img_blocksize * 2)); \
+  onepct=$$((((($(2) / 100) - 1) / img_blocksize + 1) * img_blocksize)); \
+  reserve=$$(((twoblocks > onepct ? twoblocks : onepct) + \
+               reservedblocks * img_blocksize)); \
+  maxsize=$$(($(2) - reserve)); \
+  if [ "$$total" -gt "$$maxsize" ]; then \
+    echo "error: $$printname too large ($$total > [$(2) - $$reserve])"; \
+    false; \
+  elif [ "$$total" -gt $$((maxsize - 32768)) ]; then \
+    echo "WARNING: $$printname approaching size limit ($$total now; limit $$maxsize)"; \
+  fi \
+ , \
+  true \
+ )
+endef
+
+# Like assert-max-file-size, but the second argument is a partition
+# size, which we'll convert to a max image size before checking it
+# against the files.
+#
+# $(1): The file(s) to check (often $@)
+# $(2): The partition size.
+define assert-max-image-size
+$(if $(2), \
+  $(call assert-max-file-size,$(1),$(call image-size-from-data-size,$(2))), \
+  true)
+endef
+
+
+###########################################################
+## Define device-specific radio files
+###########################################################
+
+# Copy a radio image file to the output location, and add it to
+# INSTALLED_RADIOIMAGE_TARGET.
+# $(1): filename
+define add-radio-file
+  $(eval $(call add-radio-file-internal,$(1),$(notdir $(1))))
+endef
+define add-radio-file-internal
+INSTALLED_RADIOIMAGE_TARGET += $$(PRODUCT_OUT)/$(2)
+ALL_PREBUILT += $$(PRODUCT_OUT)/$(2)
+$$(PRODUCT_OUT)/$(2) : $$(LOCAL_PATH)/$(1) | $$(ACP)
+       $$(transform-prebuilt-to-target)
+endef
+
+
+###########################################################
+# Override the package defined in $(1), setting the
+# variables listed below differently.
+#
+#  $(1): The makefile to override (relative to the source
+#        tree root)
+#  $(2): Old LOCAL_PACKAGE_NAME value.
+#  $(3): New LOCAL_PACKAGE_NAME value.
+#  $(4): New LOCAL_MANIFEST_PACKAGE_NAME value.
+#  $(5): New LOCAL_CERTIFICATE value.
+#  $(6): New LOCAL_INSTRUMENTATION_FOR value.
+#  $(7): New LOCAL_MANIFEST_INSTRUMENTATION_FOR value.
+#
+# Note that LOCAL_PACKAGE_OVERRIDES is NOT cleared in
+# clear_vars.mk.
+###########################################################
+define inherit-package
+  $(eval $(call inherit-package-internal,$(1),$(2),$(3),$(4),$(5),$(6),$(7)))
+endef
+
+define inherit-package-internal
+  LOCAL_PACKAGE_OVERRIDES \
+      := $(strip $(1))||$(strip $(2))||$(strip $(3))||$(strip $(4))||&&$(strip $(5))||&&$(strip $(6))||&&$(strip $(7)) $(LOCAL_PACKAGE_OVERRIDES)
+  include $(1)
+  LOCAL_PACKAGE_OVERRIDES \
+      := $(wordlist 1,$(words $(LOCAL_PACKAGE_OVERRIDES)), $(LOCAL_PACKAGE_OVERRIDES))
+endef
+
+# To be used with inherit-package above
+# Evalutes to true if the package was overridden
+define set-inherited-package-variables
+$(strip $(call set-inherited-package-variables-internal))
+endef
+
+define keep-or-override
+$(eval $(1) := $(if $(2),$(2),$($(1))))
+endef
+
+define set-inherited-package-variables-internal
+  $(eval _o := $(subst ||, ,$(lastword $(LOCAL_PACKAGE_OVERRIDES))))
+  $(eval _n := $(subst ||, ,$(firstword $(LOCAL_PACKAGE_OVERRIDES))))
+  $(if $(filter $(word 2,$(_n)),$(LOCAL_PACKAGE_NAME)), \
+    $(eval LOCAL_PACKAGE_NAME := $(word 3,$(_o))) \
+    $(eval LOCAL_MANIFEST_PACKAGE_NAME := $(word 4,$(_o))) \
+    $(call keep-or-override,LOCAL_CERTIFICATE,$(patsubst &&%,%,$(word 5,$(_o)))) \
+    $(call keep-or-override,LOCAL_INSTRUMENTATION_FOR,$(patsubst &&%,%,$(word 6,$(_o)))) \
+    $(call keep-or-override,LOCAL_MANIFEST_INSTRUMENTATION_FOR,$(patsubst &&%,%,$(word 7,$(_o)))) \
+    $(eval LOCAL_OVERRIDES_PACKAGES := $(sort $(LOCAL_OVERRIDES_PACKAGES) $(word 2,$(_o)))) \
+    true \
+  ,)
+endef
+
+
+###########################################################
+## Other includes
+###########################################################
+
+# -----------------------------------------------------------------
+# Rules and functions to help copy important files to DIST_DIR
+# when requested.
+include $(BUILD_SYSTEM)/distdir.mk
+
+# -----------------------------------------------------------------
+# The modules allowed to use a user tag
+include $(BUILD_SYSTEM)/user_tags.mk
+
+# broken:
+#      $(foreach file,$^,$(if $(findstring,.a,$(suffix $file)),-l$(file),$(file)))
+
+###########################################################
+## Misc notes
+###########################################################
+
+#DEPDIR = .deps
+#df = $(DEPDIR)/$(*F)
+
+#SRCS = foo.c bar.c ...
+
+#%.o : %.c
+#      @$(MAKEDEPEND); \
+#        cp $(df).d $(df).P; \
+#        sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
+#            -e '/^$$/ d' -e 's/$$/ :/' < $(df).d >> $(df).P; \
+#        rm -f $(df).d
+#      $(COMPILE.c) -o $@ $<
+
+#-include $(SRCS:%.c=$(DEPDIR)/%.P)
+
+
+#%.o : %.c
+#      $(COMPILE.c) -MD -o $@ $<
+#      @cp $*.d $*.P; \
+#        sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
+#            -e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
+#        rm -f $*.d
diff --git a/build/core/device.mk b/build/core/device.mk
new file mode 100644 (file)
index 0000000..20ff447
--- /dev/null
@@ -0,0 +1,76 @@
+#
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+_device_var_list := \
+    DEVICE_NAME \
+    DEVICE_BOARD \
+    DEVICE_REGION
+
+define dump-device
+$(info ==== $(1) ====)\
+$(foreach v,$(_device_var_list),\
+$(info DEVICES.$(1).$(v) := $(DEVICES.$(1).$(v))))\
+$(info --------)
+endef
+
+define dump-devices
+$(foreach p,$(DEVICES),$(call dump-device,$(p)))
+endef
+
+#
+# $(1): device to inherit
+#
+define inherit-device
+  $(foreach v,$(_device_var_list), \
+      $(eval $(v) := $($(v)) $(INHERIT_TAG)$(strip $(1))))
+endef
+
+#
+# $(1): device makefile list
+#
+#TODO: check to make sure that devices have all the necessary vars defined
+define import-devices
+$(call import-nodes,DEVICES,$(1),$(_device_var_list))
+endef
+
+
+#
+# $(1): short device name like "sooner"
+#
+define _resolve-short-device-name
+  $(eval dn := $(strip $(1)))
+  $(eval d := \
+      $(foreach d,$(DEVICES), \
+          $(if $(filter $(dn),$(DEVICES.$(d).DEVICE_NAME)), \
+            $(d) \
+       )) \
+   )
+  $(eval d := $(sort $(d)))
+  $(if $(filter 1,$(words $(d))), \
+    $(d), \
+    $(if $(filter 0,$(words $(d))), \
+      $(error No matches for device "$(dn)"), \
+      $(error Device "$(dn)" ambiguous: matches $(d)) \
+    ) \
+  )
+endef
+
+#
+# $(1): short device name like "sooner"
+#
+define resolve-short-device-name
+$(strip $(call _resolve-short-device-name,$(1)))
+endef
diff --git a/build/core/dex_preopt.mk b/build/core/dex_preopt.mk
new file mode 100644 (file)
index 0000000..6e0b093
--- /dev/null
@@ -0,0 +1,81 @@
+####################################
+# Dexpreopt on the boot jars
+#
+####################################
+
+# TODO: replace it with device's BOOTCLASSPATH
+DEXPREOPT_BOOT_JARS := core:bouncycastle:ext:framework:android.policy:services:core-junit
+DEXPREOPT_BOOT_JARS_MODULES := $(subst :, ,$(DEXPREOPT_BOOT_JARS))
+
+DEXPREOPT_BUILD_DIR := $(OUT_DIR)
+DEXPREOPT_PRODUCT_DIR := $(patsubst $(DEXPREOPT_BUILD_DIR)/%,%,$(PRODUCT_OUT))/dex_bootjars
+DEXPREOPT_BOOT_JAR_DIR := system/framework
+DEXPREOPT_DEXOPT := $(patsubst $(DEXPREOPT_BUILD_DIR)/%,%,$(DEXOPT))
+
+DEXPREOPT_BOOT_JAR_DIR_FULL_PATH := $(DEXPREOPT_BUILD_DIR)/$(DEXPREOPT_PRODUCT_DIR)/$(DEXPREOPT_BOOT_JAR_DIR)
+
+DEXPREOPT_BOOT_ODEXS := $(foreach b,$(DEXPREOPT_BOOT_JARS_MODULES),\
+    $(DEXPREOPT_BOOT_JAR_DIR_FULL_PATH)/$(b).odex)
+
+# If the target is a uniprocessor, then explicitly tell the preoptimizer
+# that fact. (By default, it always optimizes for an SMP target.)
+ifeq ($(TARGET_CPU_SMP),true)
+DEXPREOPT_UNIPROCESSOR :=
+else
+DEXPREOPT_UNIPROCESSOR := --uniprocessor
+endif
+
+# $(1): the .jar or .apk to remove classes.dex
+define dexpreopt-remove-classes.dex
+$(hide) $(AAPT) remove $(1) classes.dex
+endef
+
+# $(1): the input .jar or .apk file
+# $(2): the output .odex file
+define dexpreopt-one-file
+$(hide) $(DEXPREOPT) --dexopt=$(DEXPREOPT_DEXOPT) --build-dir=$(DEXPREOPT_BUILD_DIR) \
+       --product-dir=$(DEXPREOPT_PRODUCT_DIR) --boot-dir=$(DEXPREOPT_BOOT_JAR_DIR) \
+       --boot-jars=$(DEXPREOPT_BOOT_JARS) $(DEXPREOPT_UNIPROCESSOR) \
+       $(patsubst $(DEXPREOPT_BUILD_DIR)/%,%,$(1)) \
+       $(patsubst $(DEXPREOPT_BUILD_DIR)/%,%,$(2))
+endef
+
+# $(1): boot jar module name
+define _dexpreopt-boot-jar
+$(eval _dbj_jar := $(DEXPREOPT_BOOT_JAR_DIR_FULL_PATH)/$(1).jar)
+$(eval _dbj_odex := $(DEXPREOPT_BOOT_JAR_DIR_FULL_PATH)/$(1).odex)
+$(eval _dbj_jar_no_dex := $(DEXPREOPT_BOOT_JAR_DIR_FULL_PATH)/$(1)_nodex.jar)
+$(eval _dbj_src_jar := $(call intermediates-dir-for,JAVA_LIBRARIES,$(1),,COMMON)/javalib.jar)
+$(eval $(_dbj_odex): PRIVATE_DBJ_JAR := $(_dbj_jar))
+$(_dbj_odex) : $(_dbj_src_jar) | $(ACP) $(DEXPREOPT) $(DEXOPT)
+       @echo "Dexpreopt Boot Jar: $$@"
+       $(hide) rm -f $$@
+       $(hide) mkdir -p $$(dir $$@)
+       $(hide) $(ACP) -fpt $$< $$(PRIVATE_DBJ_JAR)
+       $$(call dexpreopt-one-file,$$(PRIVATE_DBJ_JAR),$$@)
+
+$(_dbj_jar_no_dex) : $(_dbj_src_jar) | $(ACP) $(AAPT)
+       $$(call copy-file-to-target)
+       $$(call dexpreopt-remove-classes.dex,$$@)
+
+$(eval _dbj_jar :=)
+$(eval _dbj_odex :=)
+$(eval _dbj_src_jar :=)
+endef
+
+$(foreach b,$(DEXPREOPT_BOOT_JARS_MODULES),$(eval $(call _dexpreopt-boot-jar,$(b))))
+
+# $(1): the rest list of boot jars
+define _build-dexpreopt-boot-jar-dependency-pair
+$(if $(filter 1,$(words $(1)))$(filter 0,$(words $(1))),,\
+       $(eval _bdbjdp_target := $(DEXPREOPT_BOOT_JAR_DIR_FULL_PATH)/$(word 2,$(1)).odex) \
+       $(eval _bdbjdp_dep := $(DEXPREOPT_BOOT_JAR_DIR_FULL_PATH)/$(word 1,$(1)).odex) \
+       $(eval $(call add-dependency,$(_bdbjdp_target),$(_bdbjdp_dep))) \
+       $(eval $(call _build-dexpreopt-boot-jar-dependency-pair,$(wordlist 2,999,$(1)))))
+endef
+
+define _build-dexpreopt-boot-jar-dependency
+$(call _build-dexpreopt-boot-jar-dependency-pair,$(DEXPREOPT_BOOT_JARS_MODULES))
+endef
+
+$(eval $(call _build-dexpreopt-boot-jar-dependency))
diff --git a/build/core/distdir.mk b/build/core/distdir.mk
new file mode 100644 (file)
index 0000000..e04938b
--- /dev/null
@@ -0,0 +1,75 @@
+#
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# When specifying "dist", the user has asked that we copy the important
+# files from this build into DIST_DIR.
+
+.PHONY: dist
+dist: ;
+
+dist_goal := $(strip $(filter dist,$(MAKECMDGOALS)))
+MAKECMDGOALS := $(strip $(filter-out dist,$(MAKECMDGOALS)))
+ifeq (,$(strip $(filter-out $(INTERNAL_MODIFIER_TARGETS),$(MAKECMDGOALS))))
+# The commandline was something like "make dist" or "make dist showcommands".
+# Add a dependency on a real target.
+dist: $(DEFAULT_GOAL)
+endif
+
+ifdef dist_goal
+
+# $(1): source file
+# $(2): destination file
+# $(3): goals that should copy the file
+#
+define copy-one-dist-file
+$(3): $(2)
+$(2): $(1)
+       @echo "Dist: $$@"
+       $$(copy-file-to-new-target-with-cp)
+endef
+
+# Other parts of the system should use this function to associate
+# certain files with certain goals.  When those goals are built
+# and "dist" is specified, the marked files will be copied to DIST_DIR.
+#
+# $(1): a list of goals  (e.g. droid, sdk, pdk, ndk)
+# $(2): the dist files to add to those goals.  If the file contains ':',
+#       the text following the colon is the name that the file is copied
+#       to under the dist directory.  Subdirs are ok, and will be created
+#       at copy time if necessary.
+define dist-for-goals
+$(foreach file,$(2), \
+  $(eval fw := $(subst :,$(space),$(file))) \
+  $(eval src := $(word 1,$(fw))) \
+  $(eval dst := $(word 2,$(fw))) \
+  $(eval dst := $(if $(dst),$(dst),$(notdir $(src)))) \
+  $(eval \
+      $(call copy-one-dist-file, \
+          $(src), \
+          $(DIST_DIR)/$(dst), \
+         $(1) \
+       ) \
+   ) \
+ )
+endef
+
+else # !dist_goal
+
+# empty definition when not building dist
+define dist-for-goals
+endef
+
+endif # !dist_goal
diff --git a/build/core/droiddoc.mk b/build/core/droiddoc.mk
new file mode 100644 (file)
index 0000000..87576dc
--- /dev/null
@@ -0,0 +1,239 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##
+##
+## Common to both droiddoc and javadoc
+##
+##
+
+LOCAL_IS_HOST_MODULE := $(call true-or-empty,$(LOCAL_IS_HOST_MODULE))
+ifeq ($(LOCAL_IS_HOST_MODULE),true)
+my_prefix:=HOST_
+else
+my_prefix:=TARGET_
+endif
+
+LOCAL_MODULE_CLASS := $(strip $(LOCAL_MODULE_CLASS))
+ifndef LOCAL_MODULE_CLASS
+$(error $(LOCAL_PATH): LOCAL_MODULE_CLASS not defined)
+endif
+
+full_src_files := $(patsubst %,$(LOCAL_PATH)/%,$(LOCAL_SRC_FILES))
+out_dir := $(OUT_DOCS)/$(LOCAL_MODULE)
+full_target := $(call doc-timestamp-for,$(LOCAL_MODULE))
+
+ifeq ($(LOCAL_DROIDDOC_SOURCE_PATH),)
+LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)
+endif
+
+ifeq ($(LOCAL_DROIDDOC_TEMPLATE_DIR),)
+LOCAL_DROIDDOC_TEMPLATE_DIR := $(SRC_DROIDDOC_DIR)/templates
+endif
+ifeq ($(LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR),)
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR := $(SRC_DROIDDOC_DIR)/templates
+endif
+
+ifeq ($(LOCAL_DROIDDOC_ASSET_DIR),)
+LOCAL_DROIDDOC_ASSET_DIR := assets
+endif
+ifeq ($(LOCAL_DROIDDOC_CUSTOM_ASSET_DIR),)
+LOCAL_DROIDDOC_CUSTOM_ASSET_DIR := assets
+endif
+
+$(full_target): PRIVATE_CLASSPATH:=$(LOCAL_CLASSPATH)
+full_java_lib_deps :=
+
+$(full_target): PRIVATE_BOOTCLASSPATH :=
+ifeq ($(BUILD_OS),linux)
+# You have to set bootclasspath for javadoc manually on linux since Java 6.
+host_jdk_rt_jar := $(dir $(HOST_JDK_TOOLS_JAR))../jre/lib/rt.jar
+$(full_target): PRIVATE_BOOTCLASSPATH := $(host_jdk_rt_jar)
+endif
+
+ifneq ($(LOCAL_IS_HOST_MODULE),true)
+
+ifeq ($(LOCAL_JAVA_LIBRARIES),)
+LOCAL_JAVA_LIBRARIES := core ext framework
+endif
+full_java_libs := $(call java-lib-files,$(LOCAL_JAVA_LIBRARIES),$(LOCAL_IS_HOST_MODULE))
+full_java_lib_deps := $(call java-lib-deps,$(LOCAL_JAVA_LIBRARIES),$(LOCAL_IS_HOST_MODULE))
+
+# we're not going to generate docs from any of these classes, but we need them
+# to build properly.
+ifneq ($(strip $(LOCAL_STATIC_JAVA_LIBRARIES)),)
+full_java_libs += $(addprefix $(LOCAL_PATH)/,$(LOCAL_STATIC_JAVA_LIBRARIES)) $(LOCAL_CLASSPATH)
+full_java_lib_deps += $(addprefix $(LOCAL_PATH)/,$(LOCAL_STATIC_JAVA_LIBRARIES)) $(LOCAL_CLASSPATH)
+endif
+
+empty :=
+space := $(empty) $(empty)
+$(full_target): PRIVATE_CLASSPATH := $(subst $(space),:,$(full_java_libs))
+
+endif # !LOCAL_IS_HOST_MODULE
+
+intermediates := $(call local-intermediates-dir)
+
+$(full_target): PRIVATE_SOURCE_PATH := $(call normalize-path-list,$(LOCAL_DROIDDOC_SOURCE_PATH))
+$(full_target): PRIVATE_JAVA_FILES := $(filter %.java,$(full_src_files))
+$(full_target): PRIVATE_JAVA_FILES += $(addprefix $($(my_prefix)OUT_COMMON_INTERMEDIATES)/, $(filter %.java,$(LOCAL_INTERMEDIATE_SOURCES)))
+$(full_target): PRIVATE_SOURCE_INTERMEDIATES_DIR := $(intermediates)/src
+$(full_target): PRIVATE_SRC_LIST_FILE := $(intermediates)/droiddoc-src-list
+
+ifneq ($(strip $(LOCAL_ADDITIONAL_JAVA_DIR)),)
+$(full_target): PRIVATE_ADDITIONAL_JAVA_DIR := $(LOCAL_ADDITIONAL_JAVA_DIR)
+endif
+
+$(full_target): PRIVATE_OUT_DIR := $(out_dir)
+$(full_target): PRIVATE_DROIDDOC_OPTIONS := $(LOCAL_DROIDDOC_OPTIONS)
+
+# Lists the input files for the doc build into a text file
+# suitable for the @ syntax of javadoc.
+# $(1): the file to create
+# $(2): files to include
+# $(3): list of directories to search for java files in
+define prepare-doc-source-list
+$(hide) mkdir -p $(dir $(1))
+$(call dump-words-to-file, $(2), $(1))
+$(hide) for d in $(3) ; do find $$d -name '*.java' >> $(1) 2> /dev/null ; done ; true
+endef
+
+ifeq (a,b)
+$(full_target): PRIVATE_PROFILING_OPTIONS := \
+    -J-agentlib:jprofilerti=port=8849 -J-Xbootclasspath/a:/Applications/jprofiler5/bin/agent.jar
+endif
+
+
+ifneq ($(strip $(LOCAL_DROIDDOC_USE_STANDARD_DOCLET)),true)
+##
+##
+## droiddoc only
+##
+##
+
+droiddoc_templates := \
+    $(shell find $(LOCAL_DROIDDOC_TEMPLATE_DIR) -type f) \
+    $(shell find $(LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR) -type f)
+
+droiddoc := \
+       $(HOST_JDK_TOOLS_JAR) \
+       $(HOST_OUT_JAVA_LIBRARIES)/droiddoc$(COMMON_JAVA_PACKAGE_SUFFIX) \
+       $(HOST_OUT_JAVA_LIBRARIES)/clearsilver$(COMMON_JAVA_PACKAGE_SUFFIX) \
+       $(HOST_OUT_SHARED_LIBRARIES)/libclearsilver-jni$(HOST_JNILIB_SUFFIX)
+
+$(full_target): PRIVATE_DOCLETPATH := $(HOST_OUT_JAVA_LIBRARIES)/clearsilver$(COMMON_JAVA_PACKAGE_SUFFIX):$(HOST_OUT_JAVA_LIBRARIES)/droiddoc$(COMMON_JAVA_PACKAGE_SUFFIX):$(HOST_OUT_JAVA_LIBRARIES)/apicheck$(COMMON_JAVA_PACKAGE_SUFFIX)
+$(full_target): PRIVATE_CURRENT_BUILD := -hdf page.build $(BUILD_ID)-$(BUILD_NUMBER)
+$(full_target): PRIVATE_CURRENT_TIME :=  -hdf page.now "$(shell date "+%d %b %Y %k:%M")"
+$(full_target): PRIVATE_TEMPLATE_DIR := $(LOCAL_DROIDDOC_TEMPLATE_DIR)
+$(full_target): PRIVATE_CUSTOM_TEMPLATE_DIR := $(LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR)
+$(full_target): PRIVATE_IN_ASSET_DIR := $(LOCAL_DROIDDOC_TEMPLATE_DIR)/$(LOCAL_DROIDDOC_ASSET_DIR)
+$(full_target): PRIVATE_IN_CUSTOM_ASSET_DIR := $(LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR)/$(LOCAL_DROIDDOC_CUSTOM_ASSET_DIR)
+$(full_target): PRIVATE_OUT_ASSET_DIR := $(out_dir)/$(LOCAL_DROIDDOC_ASSET_DIR)
+$(full_target): PRIVATE_OUT_CUSTOM_ASSET_DIR := $(out_dir)/$(LOCAL_DROIDDOC_CUSTOM_ASSET_DIR)
+ifneq ($(strip $(LOCAL_DROIDDOC_HTML_DIR)),)
+$(full_target): PRIVATE_DROIDDOC_HTML_DIR := $(foreach dir,$(LOCAL_DROIDDOC_HTML_DIR),-htmldir $(dir))
+else
+$(full_target): PRIVATE_DROIDDOC_HTML_DIR := 
+endif
+
+# TODO: not clear if this is used any more
+$(full_target): PRIVATE_LOCAL_PATH := $(LOCAL_PATH)
+
+html_dir_files := $(shell find $(LOCAL_PATH)/$(LOCAL_DROIDDOC_HTML_DIR) -type f)
+
+$(full_target): $(full_src_files) $(droiddoc_templates) $(droiddoc) $(html_dir_files) $(full_java_lib_deps) $(LOCAL_ADDITIONAL_DEPENDENCIES)
+       @echo Docs droiddoc: $(PRIVATE_OUT_DIR)
+       $(hide) mkdir -p $(dir $(full_target))
+       $(call prepare-doc-source-list,$(PRIVATE_SRC_LIST_FILE),$(PRIVATE_JAVA_FILES), \
+                       $(PRIVATE_SOURCE_INTERMEDIATES_DIR) $(PRIVATE_ADDITIONAL_JAVA_DIR))
+       $(hide) ( \
+               LD_LIBRARY_PATH=$(HOST_OUT_SHARED_LIBRARIES) \
+               javadoc \
+                \@$(PRIVATE_SRC_LIST_FILE) \
+                -J-Xmx768m \
+                -J-Djava.library.path=$(HOST_OUT_SHARED_LIBRARIES) \
+                $(PRIVATE_PROFILING_OPTIONS) \
+                -quiet \
+                -doclet DroidDoc \
+                -docletpath $(PRIVATE_DOCLETPATH) \
+                -templatedir $(PRIVATE_CUSTOM_TEMPLATE_DIR) \
+                -templatedir $(PRIVATE_TEMPLATE_DIR) \
+                $(PRIVATE_DROIDDOC_HTML_DIR) \
+                $(addprefix -bootclasspath ,$(PRIVATE_BOOTCLASSPATH)) \
+                $(addprefix -classpath ,$(PRIVATE_CLASSPATH)) \
+                -sourcepath $(PRIVATE_SOURCE_PATH)$(addprefix :,$(PRIVATE_CLASSPATH)) \
+                -d $(PRIVATE_OUT_DIR) \
+                $(PRIVATE_CURRENT_BUILD) $(PRIVATE_CURRENT_TIME) \
+                $(PRIVATE_DROIDDOC_OPTIONS) \
+        && rm -rf $(PRIVATE_OUT_ASSET_DIR) \
+        && rm -rf $(PRIVATE_OUT_CUSTOM_ASSET_DIR) \
+        && mkdir -p $(PRIVATE_OUT_ASSET_DIR) \
+        && mkdir -p $(PRIVATE_OUT_CUSTOM_ASSET_DIR) \
+        && cp -fr $(PRIVATE_IN_ASSET_DIR)/* $(PRIVATE_OUT_ASSET_DIR)/ \
+        && cp -fr $(PRIVATE_IN_CUSTOM_ASSET_DIR)/* $(PRIVATE_OUT_CUSTOM_ASSET_DIR)/ \
+        && touch -f $@ \
+    ) || (rm -rf $(PRIVATE_OUT_DIR) $(PRIVATE_SRC_LIST_FILE); exit 45)
+
+
+
+else
+##
+##
+## standard doclet only
+##
+##
+$(full_target): $(full_src_files) $(full_java_lib_deps)
+       @echo Docs javadoc: $(PRIVATE_OUT_DIR)
+       @mkdir -p $(dir $(full_target))
+       $(call prepare-doc-source-list,$(PRIVATE_SRC_LIST_FILE),$(PRIVATE_JAVA_FILES), \
+                       $(PRIVATE_SOURCE_INTERMEDIATES_DIR) $(PRIVATE_ADDITIONAL_JAVA_DIR))
+       $(hide) ( \
+               javadoc \
+                $(PRIVATE_DROIDDOC_OPTIONS) \
+                \@$(PRIVATE_SRC_LIST_FILE) \
+                -J-Xmx768m \
+                $(PRIVATE_PROFILING_OPTIONS) \
+                $(addprefix -classpath ,$(PRIVATE_CLASSPATH)) \
+                -sourcepath $(PRIVATE_SOURCE_PATH)$(addprefix :,$(PRIVATE_CLASSPATH)) \
+                -d $(PRIVATE_OUT_DIR) \
+                -quiet \
+        && touch -f $@ \
+    ) || (rm -rf $(PRIVATE_OUT_DIR) $(PRIVATE_SRC_LIST_FILE); exit 45)
+
+
+endif
+##
+##
+## Common to both droiddoc and javadoc
+##
+##
+
+
+ALL_DOCS += $(full_target)
+
+.PHONY: $(LOCAL_MODULE)-docs
+$(LOCAL_MODULE)-docs : $(full_target)
+
+# Define a rule to create a zip of these docs.
+out_zip := $(OUT_DOCS)/$(LOCAL_MODULE)-docs.zip
+$(out_zip): PRIVATE_DOCS_DIR := $(out_dir)
+$(out_zip): $(full_target)
+       @echo Package docs: $@
+       @rm -f $@
+       @mkdir -p $(dir $@)
+       $(hide) ( F=$$(pwd)/$@ ; cd $(PRIVATE_DOCS_DIR) && zip -rq $$F * )
+
+$(call dist-for-goals,docs,$(out_zip))
diff --git a/build/core/dumpvar.mk b/build/core/dumpvar.mk
new file mode 100644 (file)
index 0000000..0c58559
--- /dev/null
@@ -0,0 +1,78 @@
+# ---------------------------------------------------------------
+# the setpath shell function in envsetup.sh uses this to figure out
+# what to add to the path given the config we have chosen.
+ifeq ($(CALLED_FROM_SETUP),true)
+
+ABP:=$(PWD)/$(HOST_OUT_EXECUTABLES)
+
+ifeq ($(TARGET_SIMULATOR),true)
+       ABP:=$(ABP):$(TARGET_OUT_EXECUTABLES)
+else
+       # this should be copied to HOST_OUT_EXECUTABLES instead
+       ABP:=$(ABP):$(PWD)/prebuilt/$(HOST_PREBUILT_TAG)/toolchain/arm-eabi-4.4.3/bin
+endif
+ANDROID_BUILD_PATHS := $(ABP)
+ANDROID_PREBUILTS := prebuilt/$(HOST_PREBUILT_TAG)
+
+# The "dumpvar" stuff lets you say something like
+#
+#     CALLED_FROM_SETUP=true \
+#       make -f config/envsetup.make dumpvar-TARGET_OUT
+# or
+#     CALLED_FROM_SETUP=true \
+#       make -f config/envsetup.make dumpvar-abs-HOST_OUT_EXECUTABLES
+#
+# The plain (non-abs) version just dumps the value of the named variable.
+# The "abs" version will treat the variable as a path, and dumps an
+# absolute path to it.
+#
+dumpvar_goals := \
+       $(strip $(patsubst dumpvar-%,%,$(filter dumpvar-%,$(MAKECMDGOALS))))
+ifdef dumpvar_goals
+
+  ifneq ($(words $(dumpvar_goals)),1)
+    $(error Only one "dumpvar-" goal allowed. Saw "$(MAKECMDGOALS)")
+  endif
+
+  # If the goal is of the form "dumpvar-abs-VARNAME", then
+  # treat VARNAME as a path and return the absolute path to it.
+  absolute_dumpvar := $(strip $(filter abs-%,$(dumpvar_goals)))
+  ifdef absolute_dumpvar
+    dumpvar_goals := $(patsubst abs-%,%,$(dumpvar_goals))
+    DUMPVAR_VALUE := $(PWD)/$($(dumpvar_goals))
+    dumpvar_target := dumpvar-abs-$(dumpvar_goals)
+  else
+    DUMPVAR_VALUE := $($(dumpvar_goals))
+    dumpvar_target := dumpvar-$(dumpvar_goals)
+  endif
+
+.PHONY: $(dumpvar_target)
+$(dumpvar_target):
+       @echo $(DUMPVAR_VALUE)
+
+endif # dumpvar_goals
+
+ifneq ($(dumpvar_goals),report_config)
+PRINT_BUILD_CONFIG:=
+endif
+
+endif # CALLED_FROM_SETUP
+
+
+ifneq ($(PRINT_BUILD_CONFIG),)
+$(info ============================================)
+$(info   PLATFORM_VERSION_CODENAME=$(PLATFORM_VERSION_CODENAME))
+$(info   PLATFORM_VERSION=$(PLATFORM_VERSION))
+$(info   TARGET_PRODUCT=$(TARGET_PRODUCT))
+$(info   TARGET_BUILD_VARIANT=$(TARGET_BUILD_VARIANT))
+$(info   TARGET_SIMULATOR=$(TARGET_SIMULATOR))
+$(info   TARGET_BUILD_TYPE=$(TARGET_BUILD_TYPE))
+$(info   TARGET_BUILD_APPS=$(TARGET_BUILD_APPS))
+$(info   TARGET_ARCH=$(TARGET_ARCH))
+$(info   TARGET_ARCH_VARIANT=$(TARGET_ARCH_VARIANT))
+$(info   HOST_ARCH=$(HOST_ARCH))
+$(info   HOST_OS=$(HOST_OS))
+$(info   HOST_BUILD_TYPE=$(HOST_BUILD_TYPE))
+$(info   BUILD_ID=$(BUILD_ID))
+$(info ============================================)
+endif
diff --git a/build/core/dynamic_binary.mk b/build/core/dynamic_binary.mk
new file mode 100644 (file)
index 0000000..0fa7647
--- /dev/null
@@ -0,0 +1,164 @@
+###########################################################
+## Standard rules for building any target-side binaries
+## with dynamic linkage (dynamic libraries or executables
+## that link with dynamic libraries)
+##
+## Files including this file must define a rule to build
+## the target $(linked_module).
+###########################################################
+
+# This constraint means that we can hard-code any $(TARGET_*) variables.
+ifdef LOCAL_IS_HOST_MODULE
+$(error This file should not be used to build host binaries.  Included by (or near) $(lastword $(filter-out config/%,$(MAKEFILE_LIST))))
+endif
+
+LOCAL_UNSTRIPPED_PATH := $(strip $(LOCAL_UNSTRIPPED_PATH))
+ifeq ($(LOCAL_UNSTRIPPED_PATH),)
+  ifeq ($(LOCAL_MODULE_PATH),)
+    LOCAL_UNSTRIPPED_PATH := $(TARGET_OUT_$(LOCAL_MODULE_CLASS)_UNSTRIPPED)
+  else
+    # We have to figure out the corresponding unstripped path if LOCAL_MODULE_PATH is customized.
+    LOCAL_UNSTRIPPED_PATH := $(TARGET_OUT_UNSTRIPPED)/$(patsubst $(PRODUCT_OUT)/%,%,$(LOCAL_MODULE_PATH))
+  endif
+endif
+
+# The name of the target file, without any path prepended.
+# TODO: This duplicates logic from base_rules.mk because we need to
+#       know its results before base_rules.mk is included.
+#       Consolidate the duplicates.
+LOCAL_MODULE_STEM := $(strip $(LOCAL_MODULE_STEM))
+ifeq ($(LOCAL_MODULE_STEM),)
+  LOCAL_MODULE_STEM := $(LOCAL_MODULE)
+endif
+LOCAL_INSTALLED_MODULE_STEM := $(LOCAL_MODULE_STEM)$(LOCAL_MODULE_SUFFIX)
+LOCAL_BUILT_MODULE_STEM := $(LOCAL_INSTALLED_MODULE_STEM)
+
+# base_rules.make defines $(intermediates), but we need its value
+# before we include base_rules.  Make a guess, and verify that
+# it's correct once the real value is defined.
+guessed_intermediates := $(call local-intermediates-dir)
+
+# Define the target that is the unmodified output of the linker.
+# The basename of this target must be the same as the final output
+# binary name, because it's used to set the "soname" in the binary.
+# The includer of this file will define a rule to build this target.
+linked_module := $(guessed_intermediates)/LINKED/$(LOCAL_BUILT_MODULE_STEM)
+
+ALL_ORIGINAL_DYNAMIC_BINARIES += $(linked_module)
+
+# Because TARGET_SYMBOL_FILTER_FILE depends on ALL_ORIGINAL_DYNAMIC_BINARIES,
+# the linked_module rules won't necessarily inherit the PRIVATE_
+# variables from LOCAL_BUILT_MODULE.  This tells binary.make to explicitly
+# define the PRIVATE_ variables for linked_module as well as for
+# LOCAL_BUILT_MODULE.
+LOCAL_INTERMEDIATE_TARGETS := $(linked_module)
+
+###################################
+include $(BUILD_SYSTEM)/binary.mk
+###################################
+
+# Make sure that our guess at the value of intermediates was correct.
+ifneq ($(intermediates),$(guessed_intermediates))
+$(error Internal error: guessed path '$(guessed_intermediates)' doesn't match '$(intermediates))
+endif
+
+###########################################################
+## Compress
+###########################################################
+compress_input := $(linked_module)
+
+ifeq ($(strip $(LOCAL_COMPRESS_MODULE_SYMBOLS)),)
+  LOCAL_COMPRESS_MODULE_SYMBOLS := $(strip $(TARGET_COMPRESS_MODULE_SYMBOLS))
+endif
+
+ifeq ($(LOCAL_COMPRESS_MODULE_SYMBOLS),true)
+$(error Symbol compression not yet supported.)
+compress_output := $(intermediates)/COMPRESSED-$(LOCAL_BUILT_MODULE_STEM)
+
+#TODO: write the real $(STRIPPER) rule.
+#TODO: define a rule to build TARGET_SYMBOL_FILTER_FILE, and
+#      make it depend on ALL_ORIGINAL_DYNAMIC_BINARIES.
+$(compress_output): $(compress_input) $(TARGET_SYMBOL_FILTER_FILE) | $(ACP)
+       @echo "target Compress Symbols: $(PRIVATE_MODULE) ($@)"
+       $(copy-file-to-target)
+else
+# Skip this step.
+compress_output := $(compress_input)
+endif
+
+
+###########################################################
+## Pre-link
+###########################################################
+prelink_input := $(compress_output)
+# The output of the prelink step is the binary we want to use
+# for symbolic debugging;  the prelink step may move sections
+# around, so we have to use this version.
+prelink_output := $(LOCAL_UNSTRIPPED_PATH)/$(LOCAL_MODULE_SUBDIR)$(LOCAL_BUILT_MODULE_STEM)
+
+# Skip prelinker if it is FDO instrumentation build.
+ifneq ($(strip $(BUILD_FDO_INSTRUMENT)),)
+ifneq ($(LOCAL_NO_FDO_SUPPORT),true)
+LOCAL_PRELINK_MODULE := false
+endif
+endif
+
+ifeq ($(LOCAL_PRELINK_MODULE),true)
+$(prelink_output): $(prelink_input) $(TARGET_PRELINKER_MAP) $(APRIORI)
+       $(transform-to-prelinked)
+else
+# Don't prelink the binary, just copy it.  We can't skip this step
+# because people always expect a copy of the binary to appear
+# in the UNSTRIPPED directory.
+#
+# If the binary we're copying is acp or a prerequisite,
+# use cp(1) instead.
+ifneq ($(LOCAL_ACP_UNAVAILABLE),true)
+$(prelink_output): $(prelink_input) | $(ACP)
+       @echo "target Non-prelinked: $(PRIVATE_MODULE) ($@)"
+       $(copy-file-to-target)
+else
+$(prelink_output): $(prelink_input)
+       @echo "target Non-prelinked: $(PRIVATE_MODULE) ($@)"
+       $(copy-file-to-target-with-cp)
+endif
+endif
+
+
+###########################################################
+## Strip
+###########################################################
+strip_input := $(prelink_output)
+strip_output := $(LOCAL_BUILT_MODULE)
+
+ifeq ($(strip $(LOCAL_STRIP_MODULE)),)
+  LOCAL_STRIP_MODULE := $(strip $(TARGET_STRIP_MODULE))
+endif
+
+ifeq ($(LOCAL_STRIP_MODULE),true)
+# Strip the binary
+$(strip_output): $(strip_input) | $(TARGET_STRIP)
+       $(transform-to-stripped)
+else
+# Don't strip the binary, just copy it.  We can't skip this step
+# because a copy of the binary must appear at LOCAL_BUILT_MODULE.
+#
+# If the binary we're copying is acp or a prerequisite,
+# use cp(1) instead.
+ifneq ($(LOCAL_ACP_UNAVAILABLE),true)
+$(strip_output): $(strip_input) | $(ACP)
+       @echo "target Unstripped: $(PRIVATE_MODULE) ($@)"
+       $(copy-file-to-target)
+else
+$(strip_output): $(strip_input)
+       @echo "target Unstripped: $(PRIVATE_MODULE) ($@)"
+       $(copy-file-to-target-with-cp)
+endif
+endif # LOCAL_STRIP_MODULE
+
+
+$(cleantarget): PRIVATE_CLEAN_FILES := \
+                       $(PRIVATE_CLEAN_FILES) \
+                       $(linked_module) \
+                       $(compress_output) \
+                       $(prelink_output)
diff --git a/build/core/envsetup.mk b/build/core/envsetup.mk
new file mode 100644 (file)
index 0000000..e4c99d5
--- /dev/null
@@ -0,0 +1,277 @@
+# Variables we check:
+#     HOST_BUILD_TYPE = { release debug }
+#     TARGET_SIMULATOR = { true <null> }
+#     TARGET_BUILD_TYPE = { release debug }
+# and we output a bunch of variables, see the case statement at
+# the bottom for the full list
+#     OUT_DIR is also set to "out" if it's not already set.
+#         this allows you to set it to somewhere else if you like
+
+# Set up version information.
+include $(BUILD_SYSTEM)/version_defaults.mk
+
+# ---------------------------------------------------------------
+# If you update the build system such that the environment setup
+# or buildspec.mk need to be updated, increment this number, and
+# people who haven't re-run those will have to do so before they
+# can build.  Make sure to also update the corresponding value in
+# buildspec.mk.default and envsetup.sh.
+CORRECT_BUILD_ENV_SEQUENCE_NUMBER := 10
+
+# ---------------------------------------------------------------
+# The product defaults to generic on hardware and sim on sim
+# NOTE: This will be overridden in product_config.mk if make
+# was invoked with a PRODUCT-xxx-yyy goal.
+ifeq ($(TARGET_PRODUCT),)
+ifeq ($(TARGET_SIMULATOR),true)
+TARGET_PRODUCT := sim
+else
+TARGET_PRODUCT := full
+endif
+endif
+
+
+# the variant -- the set of files that are included for a build
+ifeq ($(strip $(TARGET_BUILD_VARIANT)),)
+TARGET_BUILD_VARIANT := eng
+endif
+
+# Read the product specs so we an get TARGET_DEVICE and other
+# variables that we need in order to locate the output files.
+include $(BUILD_SYSTEM)/product_config.mk
+
+build_variant := $(filter-out eng user userdebug tests,$(TARGET_BUILD_VARIANT))
+ifneq ($(build_variant)-$(words $(TARGET_BUILD_VARIANT)),-1)
+$(warning bad TARGET_BUILD_VARIANT: $(TARGET_BUILD_VARIANT))
+$(error must be empty or one of: eng user userdebug tests)
+endif
+
+
+
+# ---------------------------------------------------------------
+# Set up configuration for host machine.  We don't do cross-
+# compiles except for arm, so the HOST is whatever we are
+# running on
+
+UNAME := $(shell uname -sm)
+
+# HOST_OS
+ifneq (,$(findstring Linux,$(UNAME)))
+       HOST_OS := linux
+endif
+ifneq (,$(findstring Darwin,$(UNAME)))
+       HOST_OS := darwin
+endif
+ifneq (,$(findstring Macintosh,$(UNAME)))
+       HOST_OS := darwin
+endif
+ifneq (,$(findstring CYGWIN,$(UNAME)))
+       HOST_OS := windows
+endif
+
+# BUILD_OS is the real host doing the build.
+BUILD_OS := $(HOST_OS)
+
+# Under Linux, if USE_MINGW is set, we change HOST_OS to Windows to build the
+# Windows SDK. Only a subset of tools and SDK will manage to build properly.
+ifeq ($(HOST_OS),linux)
+ifneq ($(USE_MINGW),)
+       HOST_OS := windows
+endif
+endif
+
+ifeq ($(HOST_OS),)
+$(error Unable to determine HOST_OS from uname -sm: $(UNAME)!)
+endif
+
+
+# HOST_ARCH
+ifneq (,$(findstring 86,$(UNAME)))
+       HOST_ARCH := x86
+endif
+
+ifneq (,$(findstring Power,$(UNAME)))
+       HOST_ARCH := ppc
+endif
+
+BUILD_ARCH := $(HOST_ARCH)
+
+ifeq ($(HOST_ARCH),)
+$(error Unable to determine HOST_ARCH from uname -sm: $(UNAME)!)
+endif
+
+# the host build defaults to release, and it must be release or debug
+ifeq ($(HOST_BUILD_TYPE),)
+HOST_BUILD_TYPE := release
+endif
+
+ifneq ($(HOST_BUILD_TYPE),release)
+ifneq ($(HOST_BUILD_TYPE),debug)
+$(error HOST_BUILD_TYPE must be either release or debug, not '$(HOST_BUILD_TYPE)')
+endif
+endif
+
+# This is the standard way to name a directory containing prebuilt host
+# objects. E.g., prebuilt/$(HOST_PREBUILT_TAG)/cc
+ifeq ($(HOST_OS),windows)
+  HOST_PREBUILT_TAG := windows
+else
+  HOST_PREBUILT_TAG := $(HOST_OS)-$(HOST_ARCH)
+endif
+
+# Default to building dalvikvm on hosts that support it...
+ifeq ($(HOST_OS),linux)
+# ... but not if we're building the sim...
+ifneq ($(TARGET_SIMULATOR),true)
+# ... or if the if the option is already set
+ifeq ($(WITH_HOST_DALVIK),)
+       WITH_HOST_DALVIK := true
+endif
+endif
+endif
+
+
+# ---------------------------------------------------------------
+# Set up configuration for target machine.
+# The following must be set:
+#              TARGET_OS = { linux }
+#              TARGET_ARCH = { arm | x86 }
+
+
+# if we're build the simulator, HOST_* is TARGET_* (except for BUILD_TYPE)
+# otherwise  it's <arch>-linux
+ifeq ($(TARGET_SIMULATOR),true)
+ifneq ($(HOST_OS),linux)
+$(error TARGET_SIMULATOR=true is only supported under Linux)
+endif
+TARGET_ARCH := $(HOST_ARCH)
+TARGET_OS := $(HOST_OS)
+else
+ifeq ($(TARGET_ARCH),)
+TARGET_ARCH := arm
+endif
+TARGET_OS := linux
+endif
+
+# the target build type defaults to release
+ifneq ($(TARGET_BUILD_TYPE),debug)
+TARGET_BUILD_TYPE := release
+endif
+
+# ---------------------------------------------------------------
+# figure out the output directories
+
+ifeq (,$(strip $(OUT_DIR)))
+OUT_DIR := $(TOPDIR)out
+endif
+
+DEBUG_OUT_DIR := $(OUT_DIR)/debug
+
+# Move the host or target under the debug/ directory
+# if necessary.
+TARGET_OUT_ROOT_release := $(OUT_DIR)/target
+TARGET_OUT_ROOT_debug := $(DEBUG_OUT_DIR)/target
+TARGET_OUT_ROOT := $(TARGET_OUT_ROOT_$(TARGET_BUILD_TYPE))
+
+HOST_OUT_ROOT_release := $(OUT_DIR)/host
+HOST_OUT_ROOT_debug := $(DEBUG_OUT_DIR)/host
+HOST_OUT_ROOT := $(HOST_OUT_ROOT_$(HOST_BUILD_TYPE))
+
+HOST_OUT_release := $(HOST_OUT_ROOT_release)/$(HOST_OS)-$(HOST_ARCH)
+HOST_OUT_debug := $(HOST_OUT_ROOT_debug)/$(HOST_OS)-$(HOST_ARCH)
+HOST_OUT := $(HOST_OUT_$(HOST_BUILD_TYPE))
+
+BUILD_OUT := $(OUT_DIR)/host/$(BUILD_OS)-$(BUILD_ARCH)
+
+ifeq ($(TARGET_SIMULATOR),true)
+  # Any arch- or os-specific parts of the simulator (everything
+  # under product/) are actually host-dependent.
+  # But, the debug type is controlled by TARGET_BUILD_TYPE and not
+  # HOST_BUILD_TYPE.
+  TARGET_PRODUCT_OUT_ROOT := $(HOST_OUT_$(TARGET_BUILD_TYPE))/pr
+else
+  TARGET_PRODUCT_OUT_ROOT := $(TARGET_OUT_ROOT)/product
+endif
+
+TARGET_COMMON_OUT_ROOT := $(TARGET_OUT_ROOT)/common
+HOST_COMMON_OUT_ROOT := $(HOST_OUT_ROOT)/common
+
+PRODUCT_OUT := $(TARGET_PRODUCT_OUT_ROOT)/$(TARGET_DEVICE)
+
+OUT_DOCS := $(TARGET_COMMON_OUT_ROOT)/docs
+
+BUILD_OUT_EXECUTABLES:= $(BUILD_OUT)/bin
+
+HOST_OUT_EXECUTABLES:= $(HOST_OUT)/bin
+HOST_OUT_SHARED_LIBRARIES:= $(HOST_OUT)/lib
+HOST_OUT_JAVA_LIBRARIES:= $(HOST_OUT)/framework
+HOST_OUT_SDK_ADDON := $(HOST_OUT)/sdk_addon
+
+HOST_OUT_INTERMEDIATES := $(HOST_OUT)/obj
+HOST_OUT_HEADERS:= $(HOST_OUT_INTERMEDIATES)/include
+HOST_OUT_INTERMEDIATE_LIBRARIES := $(HOST_OUT_INTERMEDIATES)/lib
+HOST_OUT_STATIC_LIBRARIES := $(HOST_OUT_INTERMEDIATE_LIBRARIES)
+HOST_OUT_NOTICE_FILES:=$(HOST_OUT_INTERMEDIATES)/NOTICE_FILES
+HOST_OUT_COMMON_INTERMEDIATES := $(HOST_COMMON_OUT_ROOT)/obj
+
+TARGET_OUT_INTERMEDIATES := $(PRODUCT_OUT)/obj
+TARGET_OUT_HEADERS:= $(TARGET_OUT_INTERMEDIATES)/include
+TARGET_OUT_INTERMEDIATE_LIBRARIES := $(TARGET_OUT_INTERMEDIATES)/lib
+TARGET_OUT_COMMON_INTERMEDIATES := $(TARGET_COMMON_OUT_ROOT)/obj
+
+TARGET_OUT := $(PRODUCT_OUT)/system
+TARGET_OUT_EXECUTABLES:= $(TARGET_OUT)/bin
+TARGET_OUT_OPTIONAL_EXECUTABLES:= $(TARGET_OUT)/xbin
+TARGET_OUT_SHARED_LIBRARIES:= $(TARGET_OUT)/lib
+TARGET_OUT_JAVA_LIBRARIES:= $(TARGET_OUT)/framework
+TARGET_OUT_APPS:= $(TARGET_OUT)/app
+TARGET_OUT_KEYLAYOUT := $(TARGET_OUT)/usr/keylayout
+TARGET_OUT_KEYCHARS := $(TARGET_OUT)/usr/keychars
+TARGET_OUT_ETC := $(TARGET_OUT)/etc
+TARGET_OUT_STATIC_LIBRARIES:= $(TARGET_OUT_INTERMEDIATES)/lib
+TARGET_OUT_NOTICE_FILES:=$(TARGET_OUT_INTERMEDIATES)/NOTICE_FILES
+
+TARGET_OUT_DATA := $(PRODUCT_OUT)/data
+TARGET_OUT_DATA_EXECUTABLES:= $(TARGET_OUT_EXECUTABLES)
+TARGET_OUT_DATA_SHARED_LIBRARIES:= $(TARGET_OUT_SHARED_LIBRARIES)
+TARGET_OUT_DATA_JAVA_LIBRARIES:= $(TARGET_OUT_JAVA_LIBRARIES)
+TARGET_OUT_DATA_APPS:= $(TARGET_OUT_DATA)/app
+TARGET_OUT_DATA_KEYLAYOUT := $(TARGET_OUT_KEYLAYOUT)
+TARGET_OUT_DATA_KEYCHARS := $(TARGET_OUT_KEYCHARS)
+TARGET_OUT_DATA_ETC := $(TARGET_OUT_ETC)
+TARGET_OUT_DATA_STATIC_LIBRARIES:= $(TARGET_OUT_STATIC_LIBRARIES)
+
+TARGET_OUT_UNSTRIPPED := $(PRODUCT_OUT)/symbols
+TARGET_OUT_EXECUTABLES_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/system/bin
+TARGET_OUT_SHARED_LIBRARIES_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/system/lib
+TARGET_ROOT_OUT_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)
+TARGET_ROOT_OUT_SBIN_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/sbin
+TARGET_ROOT_OUT_BIN_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/bin
+
+TARGET_ROOT_OUT := $(PRODUCT_OUT)/root
+TARGET_ROOT_OUT_BIN := $(TARGET_ROOT_OUT)/bin
+TARGET_ROOT_OUT_SBIN := $(TARGET_ROOT_OUT)/sbin
+TARGET_ROOT_OUT_ETC := $(TARGET_ROOT_OUT)/etc
+TARGET_ROOT_OUT_USR := $(TARGET_ROOT_OUT)/usr
+
+TARGET_RECOVERY_OUT := $(PRODUCT_OUT)/recovery
+TARGET_RECOVERY_ROOT_OUT := $(TARGET_RECOVERY_OUT)/root
+
+TARGET_SYSLOADER_OUT := $(PRODUCT_OUT)/sysloader
+TARGET_SYSLOADER_ROOT_OUT := $(TARGET_SYSLOADER_OUT)/root
+TARGET_SYSLOADER_SYSTEM_OUT := $(TARGET_SYSLOADER_OUT)/root/system
+
+TARGET_INSTALLER_OUT := $(PRODUCT_OUT)/installer
+TARGET_INSTALLER_DATA_OUT := $(TARGET_INSTALLER_OUT)/data
+TARGET_INSTALLER_ROOT_OUT := $(TARGET_INSTALLER_OUT)/root
+TARGET_INSTALLER_SYSTEM_OUT := $(TARGET_INSTALLER_OUT)/root/system
+
+COMMON_MODULE_CLASSES := TARGET-NOTICE_FILES HOST-NOTICE_FILES HOST-JAVA_LIBRARIES
+
+ifeq (,$(strip $(DIST_DIR)))
+  DIST_DIR := $(OUT_DIR)/dist
+endif
+
+ifeq ($(PRINT_BUILD_CONFIG),)
+PRINT_BUILD_CONFIG := true
+endif
diff --git a/build/core/executable.mk b/build/core/executable.mk
new file mode 100644 (file)
index 0000000..623c766
--- /dev/null
@@ -0,0 +1,28 @@
+###########################################################
+## Standard rules for building an executable file.
+##
+## Additional inputs from base_rules.make:
+## None.
+###########################################################
+
+ifeq ($(strip $(LOCAL_MODULE_CLASS)),)
+LOCAL_MODULE_CLASS := EXECUTABLES
+endif
+ifeq ($(strip $(LOCAL_MODULE_SUFFIX)),)
+LOCAL_MODULE_SUFFIX := $(TARGET_EXECUTABLE_SUFFIX)
+endif
+
+# Executables are not prelinked.  If we decide to start prelinking
+# them, the LOCAL_PRELINK_MODULE definitions should be moved from
+# here and shared_library.make and consolidated in dynamic_binary.make.
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SYSTEM)/dynamic_binary.mk
+
+ifeq ($(LOCAL_FORCE_STATIC_EXECUTABLE),true)
+$(linked_module): $(TARGET_CRTBEGIN_STATIC_O) $(all_objects) $(all_libraries) $(TARGET_CRTEND_O)
+       $(transform-o-to-static-executable)
+else   
+$(linked_module): $(TARGET_CRTBEGIN_DYNAMIC_O) $(all_objects) $(all_libraries) $(TARGET_CRTEND_O)
+       $(transform-o-to-executable)
+endif
diff --git a/build/core/filter_symbols.sh b/build/core/filter_symbols.sh
new file mode 100644 (file)
index 0000000..ba5057a
--- /dev/null
@@ -0,0 +1,25 @@
+NM=$1
+
+shift
+
+PREFIX=$1
+
+shift
+
+SUFFIX=$1
+
+shift
+
+while test "$1" != ""
+do
+    $NM -g -fp $1 | while read -a line
+    do
+       type=${line[1]}
+       # if [[ "$type" != "V" && "$type" != "U" ]]; then
+       #if [[ "$type" != "W" && "$type" != "V" && "$type" != "U" ]]; then
+           echo "$PREFIX${line[0]}$SUFFIX # ${line[1]}"
+       #fi
+    done
+
+    shift
+done
diff --git a/build/core/find-jdk-tools-jar.sh b/build/core/find-jdk-tools-jar.sh
new file mode 100644 (file)
index 0000000..f555576
--- /dev/null
@@ -0,0 +1,14 @@
+if [ "x$ANDROID_JAVA_HOME" != x ] && [ -e "$ANDROID_JAVA_HOME/lib/tools.jar" ] ; then
+    echo $ANDROID_JAVA_HOME/lib/tools.jar
+else
+    JAVAC=$(which javac)
+    if [ -z "$JAVAC" ] ; then
+       echo "Please-install-JDK-6,-which-you-can-download-from-java.sun.com"
+       exit 1
+    fi
+    while [ -L $JAVAC ] ; do
+        LSLINE=$(ls -l $JAVAC)
+        JAVAC=$(echo -n $LSLINE | sed -e "s/.* -> //")
+    done
+    echo $JAVAC | sed -e "s:\(.*\)/bin/javac.*:\\1/lib/tools.jar:"
+fi
diff --git a/build/core/host_executable.mk b/build/core/host_executable.mk
new file mode 100644 (file)
index 0000000..4d90e6d
--- /dev/null
@@ -0,0 +1,20 @@
+###########################################################
+## Standard rules for building an executable file.
+##
+## Additional inputs from base_rules.make:
+## None.
+###########################################################
+
+LOCAL_IS_HOST_MODULE := true
+ifeq ($(strip $(LOCAL_MODULE_CLASS)),)
+LOCAL_MODULE_CLASS := EXECUTABLES
+endif
+ifeq ($(strip $(LOCAL_MODULE_SUFFIX)),)
+LOCAL_MODULE_SUFFIX := $(HOST_EXECUTABLE_SUFFIX)
+endif
+
+include $(BUILD_SYSTEM)/binary.mk
+
+$(LOCAL_BUILT_MODULE): $(all_objects) $(all_libraries)
+       $(transform-host-o-to-executable)
+       $(PRIVATE_POST_PROCESS_COMMAND)
diff --git a/build/core/host_java_library.mk b/build/core/host_java_library.mk
new file mode 100644 (file)
index 0000000..27174f2
--- /dev/null
@@ -0,0 +1,72 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Standard rules for building a host java library.
+#
+
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_MODULE_SUFFIX := $(COMMON_JAVA_PACKAGE_SUFFIX)
+LOCAL_IS_HOST_MODULE := true
+LOCAL_BUILT_MODULE_STEM := javalib.jar
+
+ifeq ($(LOCAL_BUILD_HOST_DEX),true)
+intermediates := $(call local-intermediates-dir)
+intermediates.COMMON := $(call local-intermediates-dir,COMMON)
+
+full_classes_jar := $(intermediates.COMMON)/classes.jar
+built_dex := $(intermediates.COMMON)/classes.dex
+
+LOCAL_INTERMEDIATE_TARGETS += \
+    $(full_classes_jar) \
+    $(built_dex)
+
+LOCAL_INTERMEDIATE_SOURCE_DIR := $(intermediates.COMMON)/src
+endif # LOCAL_BUILD_HOST_DEX
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+ifeq ($(LOCAL_BUILD_HOST_DEX),true)
+$(LOCAL_INTERMEDIATE_TARGETS): \
+       PRIVATE_CLASS_INTERMEDIATES_DIR := $(intermediates.COMMON)/classes
+$(LOCAL_INTERMEDIATE_TARGETS): \
+       PRIVATE_SOURCE_INTERMEDIATES_DIR := $(LOCAL_INTERMEDIATE_SOURCE_DIR)
+
+$(cleantarget): PRIVATE_CLEAN_FILES += $(intermediates.COMMON)
+
+$(full_classes_jar): PRIVATE_JAVACFLAGS := $(LOCAL_JAVACFLAGS)
+$(full_classes_jar): $(java_sources) $(java_resource_sources) $(full_java_lib_deps) $(jar_manifest_file)
+       $(transform-host-java-to-package)
+
+$(built_dex): PRIVATE_INTERMEDIATES_DIR := $(intermediates.COMMON)
+$(built_dex): PRIVATE_DX_FLAGS := $(LOCAL_DX_FLAGS)
+$(built_dex): $(full_classes_jar) $(DX)
+       $(transform-classes.jar-to-dex)
+
+$(LOCAL_BUILT_MODULE): PRIVATE_DEX_FILE := $(built_dex)
+$(LOCAL_BUILT_MODULE): $(built_dex) $(java_resource_sources) | $(AAPT)
+       @echo "Host Jar: $(PRIVATE_MODULE) ($@)"
+       $(create-empty-package)
+       $(add-dex-to-package)
+ifneq ($(extra_jar_args),)
+       $(add-java-resources-to-package)
+endif
+
+else
+$(LOCAL_BUILT_MODULE): PRIVATE_JAVACFLAGS := $(LOCAL_JAVACFLAGS)
+$(LOCAL_BUILT_MODULE): $(java_sources) $(java_resource_sources) $(full_java_lib_deps) $(jar_manifest_file)
+       $(transform-host-java-to-package)
+endif  # LOCAL_BUILD_HOST_DEX
diff --git a/build/core/host_prebuilt.mk b/build/core/host_prebuilt.mk
new file mode 100644 (file)
index 0000000..7baab69
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_IS_HOST_MODULE := true
+include $(BUILD_MULTI_PREBUILT)
diff --git a/build/core/host_shared_library.mk b/build/core/host_shared_library.mk
new file mode 100644 (file)
index 0000000..f78b17b
--- /dev/null
@@ -0,0 +1,29 @@
+###########################################################
+## Standard rules for building a normal shared library.
+##
+## Additional inputs from base_rules.make:
+## None.
+##
+## LOCAL_MODULE_SUFFIX will be set for you.
+###########################################################
+
+LOCAL_IS_HOST_MODULE := true
+
+ifeq ($(strip $(LOCAL_MODULE_CLASS)),)
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+endif
+ifeq ($(strip $(LOCAL_MODULE_SUFFIX)),)
+LOCAL_MODULE_SUFFIX := $(HOST_SHLIB_SUFFIX)
+endif
+ifneq ($(strip $(OVERRIDE_BUILT_MODULE_PATH)),)
+$(error $(LOCAL_PATH): Illegal use of OVERRIDE_BUILT_MODULE_PATH)
+endif
+
+# Put the built modules of all shared libraries in a common directory
+# to simplify the link line.
+OVERRIDE_BUILT_MODULE_PATH := $(HOST_OUT_INTERMEDIATE_LIBRARIES)
+
+include $(BUILD_SYSTEM)/binary.mk
+
+$(LOCAL_BUILT_MODULE): $(all_objects) $(all_libraries) $(LOCAL_ADDITIONAL_DEPENDENCIES)
+       $(transform-host-o-to-shared-lib)
diff --git a/build/core/host_static_library.mk b/build/core/host_static_library.mk
new file mode 100644 (file)
index 0000000..39c99ee
--- /dev/null
@@ -0,0 +1,24 @@
+###########################################################
+## Standard rules for building a static library for the host.
+##
+## Additional inputs from base_rules.make:
+## None.
+##
+## LOCAL_MODULE_SUFFIX will be set for you.
+###########################################################
+
+ifeq ($(strip $(LOCAL_MODULE_CLASS)),)
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+endif
+ifeq ($(strip $(LOCAL_MODULE_SUFFIX)),)
+LOCAL_MODULE_SUFFIX := .a
+endif
+LOCAL_UNINSTALLABLE_MODULE := true
+
+LOCAL_IS_HOST_MODULE := true
+
+include $(BUILD_SYSTEM)/binary.mk
+
+$(LOCAL_BUILT_MODULE): $(built_whole_libraries)
+$(LOCAL_BUILT_MODULE): $(all_objects)
+       $(transform-host-o-to-static-lib)
diff --git a/build/core/java.mk b/build/core/java.mk
new file mode 100644 (file)
index 0000000..35b0343
--- /dev/null
@@ -0,0 +1,336 @@
+# Requires:
+# LOCAL_MODULE_SUFFIX
+# LOCAL_MODULE_CLASS
+# all_res_assets
+
+# Make sure there's something to build.
+# It's possible to build a package that doesn't contain any classes.
+ifeq (,$(strip $(LOCAL_SRC_FILES)$(all_res_assets)))
+$(error $(LOCAL_PATH): Target java module does not define any source or resource files)
+endif
+
+LOCAL_NO_STANDARD_LIBRARIES:=$(strip $(LOCAL_NO_STANDARD_LIBRARIES))
+LOCAL_SDK_VERSION:=$(strip $(LOCAL_SDK_VERSION))
+
+ifneq ($(LOCAL_SDK_VERSION),)
+  ifeq ($(LOCAL_NO_STANDARD_LIBRARIES),true)
+    $(error $(LOCAL_PATH): Must not define both LOCAL_NO_STANDARD_LIBRARIES and LOCAL_SDK_VERSION)
+  else
+    ifeq ($(strip $(filter $(LOCAL_SDK_VERSION),$(TARGET_AVAILABLE_SDK_VERSIONS))),)
+      $(error $(LOCAL_PATH): Invalid LOCAL_SDK_VERSION '$(LOCAL_SDK_VERSION)' \
+             Choices are: $(TARGET_AVAILABLE_SDK_VERSIONS))
+    else
+      ifeq ($(LOCAL_SDK_VERSION),current)
+        LOCAL_JAVA_LIBRARIES := android_stubs_$(LOCAL_SDK_VERSION) $(LOCAL_JAVA_LIBRARIES)
+      else
+        LOCAL_JAVA_LIBRARIES := sdk_v$(LOCAL_SDK_VERSION) $(LOCAL_JAVA_LIBRARIES)
+      endif
+    endif
+  endif
+else
+  ifneq ($(LOCAL_NO_STANDARD_LIBRARIES),true)
+    LOCAL_JAVA_LIBRARIES := core core-junit ext framework $(LOCAL_JAVA_LIBRARIES)
+  endif
+endif
+
+proto_sources := $(filter %.proto,$(LOCAL_SRC_FILES))
+ifneq ($(proto_sources),)
+ifeq ($(LOCAL_PROTOC_OPTIMIZE_TYPE),micro)
+    LOCAL_STATIC_JAVA_LIBRARIES += libprotobuf-java-2.3.0-micro
+else
+    LOCAL_STATIC_JAVA_LIBRARIES += libprotobuf-java-2.3.0-lite
+endif
+endif
+
+LOCAL_JAVA_LIBRARIES := $(sort $(LOCAL_JAVA_LIBRARIES))
+
+LOCAL_BUILT_MODULE_STEM := $(strip $(LOCAL_BUILT_MODULE_STEM))
+ifeq ($(LOCAL_BUILT_MODULE_STEM),)
+$(error $(LOCAL_PATH): Target java template must define LOCAL_BUILT_MODULE_STEM)
+endif
+ifneq ($(filter classes-compiled.jar classes.jar,$(LOCAL_BUILT_MODULE_STEM)),)
+$(error LOCAL_BUILT_MODULE_STEM may not be "$(LOCAL_BUILT_MODULE_STEM)")
+endif
+
+
+##############################################################################
+# Define the intermediate targets before including base_rules so they get
+# the correct environment.
+##############################################################################
+
+intermediates := $(call local-intermediates-dir)
+intermediates.COMMON := $(call local-intermediates-dir,COMMON)
+
+# Emma source code coverage
+ifneq ($(EMMA_INSTRUMENT),true)
+LOCAL_NO_EMMA_INSTRUMENT := true
+LOCAL_NO_EMMA_COMPILE := true
+endif
+
+# Choose leaf name for the compiled jar file.
+ifneq ($(LOCAL_NO_EMMA_COMPILE),true)
+full_classes_compiled_jar_leaf := classes-no-debug-var.jar
+built_dex_intermediate_leaf := classes-no-local.dex
+else
+full_classes_compiled_jar_leaf := classes-full-debug.jar
+built_dex_intermediate_leaf := classes-with-local.dex
+endif
+
+LOCAL_PROGUARD_ENABLED:=$(strip $(LOCAL_PROGUARD_ENABLED))
+ifeq ($(LOCAL_PROGUARD_ENABLED),disabled)
+LOCAL_PROGUARD_ENABLED :=
+endif
+
+# By giving different file name, files can be updated correctly when switching
+# between builds with and without Proguard enabled.
+# Note that ANY intermediate targets between the proguard and
+# the final built_dex should be differently named!
+ifdef LOCAL_PROGUARD_ENABLED
+proguard_jar_leaf := proguard.classes.jar
+built_dex_intermediate_leaf := proguard.$(built_dex_intermediate_leaf)
+built_dex_leaf := progaurd.classes.dex
+else
+proguard_jar_leaf := noproguard.classes.jar
+built_dex_intermediate_leaf := noproguard.$(built_dex_intermediate_leaf)
+built_dex_leaf := noproguard.classes.dex
+endif
+
+full_classes_compiled_jar := $(intermediates.COMMON)/$(full_classes_compiled_jar_leaf)
+jarjar_leaf := classes-jarjar.jar
+full_classes_jarjar_jar := $(intermediates.COMMON)/$(jarjar_leaf)
+emma_intermediates_dir := $(intermediates.COMMON)/emma_out
+# emma is hardcoded to use the leaf name of its input for the output file --
+# only the output directory can be changed
+full_classes_emma_jar := $(emma_intermediates_dir)/lib/$(jarjar_leaf)
+full_classes_proguard_jar := $(intermediates.COMMON)/$(proguard_jar_leaf)
+built_dex_intermediate := $(intermediates.COMMON)/$(built_dex_intermediate_leaf)
+full_classes_stubs_jar := $(intermediates.COMMON)/stubs.jar
+
+# full_classes_jar and built_dex are cleared below, and re-set if we really need them.
+full_classes_jar := $(intermediates.COMMON)/classes.jar
+built_dex := $(intermediates.COMMON)/$(built_dex_leaf)
+
+LOCAL_INTERMEDIATE_TARGETS += \
+    $(full_classes_compiled_jar) \
+    $(full_classes_jarjar_jar) \
+    $(full_classes_emma_jar) \
+    $(full_classes_jar) \
+    $(full_classes_proguard_jar) \
+    $(built_dex_intermediate) \
+    $(built_dex) \
+    $(full_classes_stubs_jar)
+
+
+LOCAL_INTERMEDIATE_SOURCE_DIR := $(intermediates.COMMON)/src
+
+# TODO: It looks like the only thing we need from base_rules is
+# all_java_sources.  See if we can get that by adding a
+# common_java.mk, and moving the include of base_rules.mk to
+# after all the declarations.
+
+#######################################
+include $(BUILD_SYSTEM)/base_rules.mk
+#######################################
+
+# We use intermediates.COMMON because the classes.jar/.dex files will be
+# common even if LOCAL_BUILT_MODULE isn't.
+#
+# Override some target variables that base_rules set up for us.
+$(LOCAL_INTERMEDIATE_TARGETS): \
+       PRIVATE_CLASS_INTERMEDIATES_DIR := $(intermediates.COMMON)/classes
+$(LOCAL_INTERMEDIATE_TARGETS): \
+       PRIVATE_SOURCE_INTERMEDIATES_DIR := $(LOCAL_INTERMEDIATE_SOURCE_DIR)
+
+# Since we're using intermediates.COMMON, make sure that it gets cleaned
+# properly.
+$(cleantarget): PRIVATE_CLEAN_FILES += $(intermediates.COMMON)
+
+# If the module includes java code (i.e., it's not framework-res), compile it.
+full_classes_jar :=
+built_dex :=
+ifneq (,$(strip $(all_java_sources)))
+
+# If LOCAL_BUILT_MODULE_STEM wasn't overridden by our caller,
+# full_classes_jar will be the same module as LOCAL_BUILT_MODULE.
+# Otherwise, the caller will define it as a prerequisite of
+# LOCAL_BUILT_MODULE, so it will inherit the necessary PRIVATE_*
+# variable definitions.
+full_classes_jar := $(intermediates.COMMON)/classes.jar
+built_dex := $(intermediates.COMMON)/$(built_dex_leaf)
+
+# Droiddoc isn't currently able to generate stubs for modules, so we're just
+# allowing it to use the classes.jar as the "stubs" that would be use to link
+# against, for the cases where someone needs the jar to link against.
+# - Use the classes.jar instead of the handful of other intermediates that
+#   we have, because it's the most processed, but still hasn't had dex run on
+#   it, so it's closest to what's on the device.
+# - This extra copy, with the dependency on LOCAL_BUILT_MODULE allows the
+#   PRIVATE_ vars to be preserved.
+$(full_classes_stubs_jar): PRIVATE_SOURCE_FILE := $(full_classes_jar)
+$(full_classes_stubs_jar) : $(LOCAL_BUILT_MODULE) | $(ACP)
+       @echo Copying $(PRIVATE_SOURCE_FILE)
+       $(hide) $(ACP) -fp $(PRIVATE_SOURCE_FILE) $@
+ALL_MODULES.$(LOCAL_MODULE).STUBS := $(full_classes_stubs_jar)
+
+# Compile the java files to a .jar file.
+# This intentionally depends on java_sources, not all_java_sources.
+# Deps for generated source files must be handled separately,
+# via deps on the target that generates the sources.
+$(full_classes_compiled_jar): PRIVATE_JAVACFLAGS := $(LOCAL_JAVACFLAGS)
+$(full_classes_compiled_jar): $(java_sources) $(java_resource_sources) $(full_java_lib_deps) $(jar_manifest_file) \
+       $(RenderScript_file_stamp) $(proto_java_sources_file_stamp)
+       $(transform-java-to-classes.jar)
+
+# All of the rules after full_classes_compiled_jar are very unlikely
+# to fail except for bugs in their respective tools.  If you would
+# like to run these rules, add the "all" modifier goal to the make
+# command line.
+# This overwrites the value defined in base_rules.mk.  That's a little
+# dirty.  It's preferable to set LOCAL_CHECKED_MODULE, but this has to
+# be done after the inclusion of base_rules.mk.
+ALL_MODULES.$(LOCAL_MODULE).CHECKED := $(full_classes_compiled_jar)
+
+$(full_classes_compiled_jar): PRIVATE_JAVAC_DEBUG_FLAGS := -g
+
+# Run jarjar if necessary, otherwise just copy the file.
+ifneq ($(strip $(LOCAL_JARJAR_RULES)),)
+$(full_classes_jarjar_jar): PRIVATE_JARJAR_RULES := $(LOCAL_JARJAR_RULES)
+$(full_classes_jarjar_jar): $(full_classes_compiled_jar) | $(JARJAR)
+       @echo JarJar: $@
+       $(hide) java -jar $(JARJAR) process $(PRIVATE_JARJAR_RULES) $< $@
+else
+$(full_classes_jarjar_jar): $(full_classes_compiled_jar) | $(ACP)
+       @echo Copying: $@
+       $(hide) $(ACP) $< $@
+endif
+
+ifeq ($(LOCAL_IS_STATIC_JAVA_LIBRARY),true)
+# Skip adding emma instrumentation to class files if this is a static library,
+# since it will be instrumented by the package that includes it
+LOCAL_NO_EMMA_INSTRUMENT:= true
+endif
+
+ifneq ($(LOCAL_NO_EMMA_INSTRUMENT),true)
+$(full_classes_emma_jar): PRIVATE_EMMA_COVERAGE_FILE := $(intermediates.COMMON)/coverage.em
+$(full_classes_emma_jar): PRIVATE_EMMA_INTERMEDIATES_DIR := $(emma_intermediates_dir)
+# module level coverage filter can be defined using LOCAL_EMMA_COVERAGE_FILTER
+# in Android.mk
+ifdef LOCAL_EMMA_COVERAGE_FILTER
+$(full_classes_emma_jar): PRIVATE_EMMA_COVERAGE_FILTER := $(LOCAL_EMMA_COVERAGE_FILTER)
+else
+# by default, avoid applying emma instrumentation onto emma classes itself,
+# otherwise there will be exceptions thrown
+$(full_classes_emma_jar): PRIVATE_EMMA_COVERAGE_FILTER := *,-emma,-emmarun,-com.vladium.*
+endif
+# this rule will generate both $(PRIVATE_EMMA_COVERAGE_FILE) and
+# $(full_classes_emma_jar)
+$(full_classes_emma_jar): $(full_classes_jarjar_jar) | $(EMMA_JAR)
+       $(transform-classes.jar-to-emma)
+$(PRIVATE_EMMA_COVERAGE_FILE): $(full_classes_emma_jar)
+
+# tell proguard to load emma jar
+LOCAL_PROGUARD_FLAGS := $(LOCAL_PROGUARD_FLAGS) $(addprefix -libraryjars ,$(EMMA_JAR))
+else
+$(full_classes_emma_jar): $(full_classes_jarjar_jar) | $(ACP)
+       @echo Copying: $@
+       $(copy-file-to-target)
+endif
+
+# Keep a copy of the jar just before proguard processing.
+$(full_classes_jar): $(full_classes_emma_jar) | $(ACP)
+       @echo Copying: $@
+       $(hide) $(ACP) $< $@
+
+# Run proguard if necessary, otherwise just copy the file.
+proguard_dictionary := $(intermediates.COMMON)/proguard_dictionary
+# Proguard doesn't like a class in both library and the jar to be processed.
+proguard_full_java_libs := $(filter-out $(full_static_java_libs),$(full_java_libs))
+proguard_flags := $(addprefix -libraryjars ,$(proguard_full_java_libs)) \
+                  -include $(BUILD_SYSTEM)/proguard.flags \
+                  -forceprocessing \
+                  -printmapping $(proguard_dictionary)
+# If this is a test package, add proguard keep flags for tests.
+ifneq ($(strip $(LOCAL_INSTRUMENTATION_FOR)$(filter tests,$(LOCAL_MODULE_TAGS))$(filter android.test.runner,$(LOCAL_JAVA_LIBRARIES))),)
+proguard_flags := $(proguard_flags) -include $(BUILD_SYSTEM)/proguard_tests.flags
+endif # test package
+
+ifneq ($(LOCAL_PROGUARD_ENABLED),)
+ifeq ($(LOCAL_PROGUARD_ENABLED),full)
+    # full
+else
+ifeq ($(LOCAL_PROGUARD_ENABLED),optonly)
+    # optonly
+    proguard_flags += -dontobfuscate
+else
+ifeq ($(LOCAL_PROGUARD_ENABLED),custom)
+    # custom
+else
+    $(warning while processing: $(LOCAL_MODULE))
+    $(error invalid value for LOCAL_PROGUARD_ENABLED: $(LOCAL_PROGUARD_ENABLED))
+endif # custom
+endif # optonly
+endif # full
+endif # LOCAL_PROGUARD_ENABLED
+
+proguard_flag_files := $(addprefix $(LOCAL_PATH)/, $(LOCAL_PROGUARD_FLAG_FILES))
+LOCAL_PROGUARD_FLAGS += $(addprefix -include , $(proguard_flag_files))
+
+$(full_classes_proguard_jar): PRIVATE_PROGUARD_ENABLED:=$(LOCAL_PROGUARD_ENABLED)
+$(full_classes_proguard_jar): PRIVATE_PROGUARD_FLAGS := $(proguard_flags) $(LOCAL_PROGUARD_FLAGS)
+$(full_classes_proguard_jar): PRIVATE_INSTRUMENTATION_FOR:=$(strip $(LOCAL_INSTRUMENTATION_FOR))
+$(full_classes_proguard_jar) : $(full_classes_jar) $(proguard_flag_files) | $(ACP) $(PROGUARD)
+       $(call transform-jar-to-proguard)
+
+ALL_MODULES.$(LOCAL_MODULE).PROGUARD_ENABLED:=$(LOCAL_PROGUARD_ENABLED)
+
+# If you instrument class files that have local variable debug information in
+# them emma does not correctly maintain the local variable table.
+# This will cause an error when you try to convert the class files for Android.
+# The workaround here is to build different dex file here based on emma switch
+# then later copy into classes.dex. When emma is on, dx is run with --no-locals
+# option to remove local variable information
+
+# Override PRIVATE_INTERMEDIATES_DIR so that install-dex-debug
+# will work even when intermediates != intermediates.COMMON.
+$(built_dex_intermediate): PRIVATE_INTERMEDIATES_DIR := $(intermediates.COMMON)
+$(built_dex_intermediate): PRIVATE_DX_FLAGS := $(LOCAL_DX_FLAGS)
+ifneq ($(LOCAL_NO_EMMA_COMPILE),true)
+$(built_dex_intermediate): PRIVATE_DX_FLAGS += --no-locals
+endif
+$(built_dex_intermediate): $(full_classes_proguard_jar) $(DX)
+       $(transform-classes.jar-to-dex)
+$(built_dex): $(built_dex_intermediate) | $(ACP)
+       @echo Copying: $@
+       $(hide) $(ACP) $< $@
+ifneq ($(GENERATE_DEX_DEBUG),)
+       $(install-dex-debug)
+endif
+
+findbugs_xml := $(intermediates.COMMON)/findbugs.xml
+$(findbugs_xml) : PRIVATE_JAR_FILE := $(full_classes_jar)
+$(findbugs_xml) : PRIVATE_AUXCLASSPATH := $(addprefix -auxclasspath ,$(strip \
+                                                               $(call normalize-path-list,$(filter %.jar,\
+                                                                               $(full_java_libs)))))
+# We can't depend directly on full_classes_jar because the PRIVATE_
+# vars won't be set up correctly.
+$(findbugs_xml) : $(LOCAL_BUILT_MODULE)
+       @echo Findbugs: $@
+       $(hide) $(FINDBUGS) -textui -effort:min -xml:withMessages \
+               $(PRIVATE_AUXCLASSPATH) \
+               $(PRIVATE_JAR_FILE) \
+               > $@
+
+ALL_FINDBUGS_FILES += $(findbugs_xml)
+
+findbugs_html := $(PRODUCT_OUT)/findbugs/$(LOCAL_MODULE).html
+$(findbugs_html) : PRIVATE_XML_FILE := $(findbugs_xml)
+$(LOCAL_MODULE)-findbugs : $(findbugs_html)
+$(findbugs_html) : $(findbugs_xml)
+       @mkdir -p $(dir $@)
+       @echo ConvertXmlToText: $@
+       $(hide) prebuilt/common/findbugs/bin/convertXmlToText -html:fancy.xsl $(PRIVATE_XML_FILE) \
+       > $@
+
+$(LOCAL_MODULE)-findbugs : $(findbugs_html)
+
+endif
diff --git a/build/core/java_library.mk b/build/core/java_library.mk
new file mode 100644 (file)
index 0000000..abc4728
--- /dev/null
@@ -0,0 +1,96 @@
+###########################################################
+## Standard rules for building a java library.
+##
+###########################################################
+
+ifdef LOCAL_IS_HOST_MODULE
+$(error $(LOCAL_PATH): Host java libraries must use BUILD_HOST_JAVA_LIBRARY)
+endif
+
+LOCAL_MODULE_SUFFIX := $(COMMON_JAVA_PACKAGE_SUFFIX)
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+ifneq (,$(LOCAL_ASSET_DIR))
+$(error $(LOCAL_PATH): Target java libraries may not set LOCAL_ASSET_DIR)
+endif
+
+ifneq (,$(LOCAL_RESOURCE_DIR))
+$(error $(LOCAL_PATH): Target java libraries may not set LOCAL_RESOURCE_DIR)
+endif
+
+#xxx base_rules.mk looks at this
+all_res_assets :=
+
+LOCAL_BUILT_MODULE_STEM := javalib.jar
+
+intermediates.COMMON := $(call local-intermediates-dir,COMMON)
+
+# This file will be the one that other modules should depend on.
+common_javalib.jar := $(intermediates.COMMON)/$(LOCAL_BUILT_MODULE_STEM)
+LOCAL_INTERMEDIATE_TARGETS += $(common_javalib.jar)
+
+ifeq (true,$(WITH_DEXPREOPT))
+ifndef LOCAL_DEX_PREOPT
+LOCAL_DEX_PREOPT := true
+endif
+endif
+
+#################################
+include $(BUILD_SYSTEM)/java.mk
+#################################
+
+ifeq ($(LOCAL_IS_STATIC_JAVA_LIBRARY),true)
+# No dex or resources; all we want are the .class files.
+$(common_javalib.jar) : $(full_classes_jar)
+       @echo "target Static Jar: $(PRIVATE_MODULE) ($@)"
+       $(copy-file-to-target)
+
+$(LOCAL_BUILT_MODULE): $(common_javalib.jar)
+       $(copy-file-to-target)
+
+else # !LOCAL_IS_STATIC_JAVA_LIBRARY
+
+$(common_javalib.jar): PRIVATE_DEX_FILE := $(built_dex)
+$(common_javalib.jar) : $(built_dex) $(java_resource_sources) | $(AAPT)
+       @echo "target Jar: $(PRIVATE_MODULE) ($@)"
+       $(create-empty-package)
+       $(add-dex-to-package)
+ifneq ($(extra_jar_args),)
+       $(add-java-resources-to-package)
+endif
+
+ifeq ($(LOCAL_DEX_PREOPT),true)
+dexpreopt_boot_jar_module := $(filter $(LOCAL_MODULE),$(DEXPREOPT_BOOT_JARS_MODULES))
+ifneq ($(dexpreopt_boot_jar_module),)
+# boot jar's rules are defined in dex_preopt.mk
+dexpreopted_boot_jar := $(DEXPREOPT_BOOT_JAR_DIR_FULL_PATH)/$(dexpreopt_boot_jar_module)_nodex.jar
+$(LOCAL_BUILT_MODULE) : $(dexpreopted_boot_jar) | $(ACP)
+       $(call copy-file-to-target)
+
+dexpreopted_boot_odex := $(DEXPREOPT_BOOT_JAR_DIR_FULL_PATH)/$(dexpreopt_boot_jar_module).odex
+built_odex := $(basename $(LOCAL_BUILT_MODULE)).odex
+$(built_odex) : $(dexpreopted_boot_odex) | $(ACP)
+       $(call copy-file-to-target)
+
+else # dexpreopt_boot_jar_module
+built_odex := $(basename $(LOCAL_BUILT_MODULE)).odex
+$(built_odex): PRIVATE_MODULE := $(LOCAL_MODULE)
+# Make sure the boot jars get dex-preopt-ed first
+$(built_odex) : $(DEXPREOPT_BOOT_ODEXS)
+$(built_odex) : $(common_javalib.jar) | $(DEXPREOPT) $(DEXOPT)
+       @echo "Dexpreopt Jar: $(PRIVATE_MODULE) ($@)"
+       $(hide) rm -f $@
+       $(call dexpreopt-one-file,$<,$@)
+
+$(LOCAL_BUILT_MODULE) : $(common_javalib.jar) | $(ACP) $(AAPT)
+       $(call copy-file-to-target)
+       $(call dexpreopt-remove-classes.dex,$@)
+
+endif # dexpreopt_boot_jar_module
+
+else # LOCAL_DEX_PREOPT
+$(LOCAL_BUILT_MODULE) : $(common_javalib.jar) | $(ACP)
+       $(call copy-file-to-target)
+
+endif # LOCAL_DEX_PREOPT
+endif # !LOCAL_IS_STATIC_JAVA_LIBRARY
diff --git a/build/core/key_char_map.mk b/build/core/key_char_map.mk
new file mode 100644 (file)
index 0000000..0f112f2
--- /dev/null
@@ -0,0 +1,27 @@
+###########################################################
+## Standard rules for building an executable file.
+##
+## Additional inputs from base_rules.make:
+## None.
+###########################################################
+
+ifeq ($(strip $(LOCAL_MODULE_CLASS)),)
+LOCAL_MODULE_CLASS := KEYCHARS
+endif
+ifeq ($(strip $(LOCAL_MODULE_SUFFIX)),)
+LOCAL_MODULE_SUFFIX := .bin
+endif
+
+LOCAL_MODULE := $(LOCAL_SRC_FILES)
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+full_src_files := $(addprefix $(LOCAL_PATH)/,$(LOCAL_SRC_FILES))
+
+$(LOCAL_BUILT_MODULE) : PRIVATE_SRC_FILES := $(full_src_files)
+
+$(LOCAL_BUILT_MODULE) : $(full_src_files) $(KCM)
+       @echo KeyCharMap: $@
+       @mkdir -p $(dir $@)
+       $(hide) $(KCM) $(PRIVATE_SRC_FILES) $@
+    
diff --git a/build/core/main.mk b/build/core/main.mk
new file mode 100644 (file)
index 0000000..0a7d3bf
--- /dev/null
@@ -0,0 +1,797 @@
+# Only use ANDROID_BUILD_SHELL to wrap around bash.
+# DO NOT use other shells such as zsh.
+ifdef ANDROID_BUILD_SHELL
+SHELL := $(ANDROID_BUILD_SHELL)
+else
+# Use bash, not whatever shell somebody has installed as /bin/sh
+# This is repeated in config.mk, since envsetup.sh runs that file
+# directly.
+SHELL := /bin/bash
+endif
+
+# this turns off the suffix rules built into make
+.SUFFIXES:
+
+# If a rule fails, delete $@.
+.DELETE_ON_ERROR:
+
+# Figure out where we are.
+#TOP := $(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
+#TOP := $(patsubst %/,%,$(TOP))
+
+# TOPDIR is the normal variable you should use, because
+# if we are executing relative to the current directory
+# it can be "", whereas TOP must be "." which causes
+# pattern matching probles when make strips off the
+# trailing "./" from paths in various places.
+#ifeq ($(TOP),.)
+#TOPDIR :=
+#else
+#TOPDIR := $(TOP)/
+#endif
+
+# check for broken versions of make
+ifeq (0,$(shell expr $$(echo $(MAKE_VERSION) | sed "s/[^0-9\.].*//") = 3.81))
+$(warning ********************************************************************************)
+$(warning *  You are using version $(MAKE_VERSION) of make.)
+$(warning *  Android can only be built by version 3.81.)
+$(warning *  see http://source.android.com/source/download.html)
+$(warning ********************************************************************************)
+$(error stopping)
+endif
+
+TOP := .
+TOPDIR :=
+
+BUILD_SYSTEM := $(TOPDIR)build/core
+
+# This is the default target.  It must be the first declared target.
+.PHONY: droid
+DEFAULT_GOAL := droid
+$(DEFAULT_GOAL):
+
+# Used to force goals to build.  Only use for conditionally defined goals.
+.PHONY: FORCE
+FORCE:
+
+# Set up various standard variables based on configuration
+# and host information.
+include $(BUILD_SYSTEM)/config.mk
+
+# This allows us to force a clean build - included after the config.make
+# environment setup is done, but before we generate any dependencies.  This
+# file does the rm -rf inline so the deps which are all done below will
+# be generated correctly
+include $(BUILD_SYSTEM)/cleanbuild.mk
+
+VERSION_CHECK_SEQUENCE_NUMBER := 2
+-include $(OUT_DIR)/versions_checked.mk
+ifneq ($(VERSION_CHECK_SEQUENCE_NUMBER),$(VERSIONS_CHECKED))
+
+$(info Checking build tools versions...)
+
+ifeq ($(BUILD_OS),linux)
+build_arch := $(shell uname -m)
+ifneq (64,$(findstring 64,$(build_arch)))
+$(warning ************************************************************)
+$(warning You are attempting to build on a 32-bit system.)
+$(warning Only 64-bit build environments are supported beyond froyo/2.2.)
+$(warning ************************************************************)
+$(error stop)
+endif
+endif
+
+ifneq ($(HOST_OS),windows)
+ifneq ($(HOST_OS)-$(HOST_ARCH),darwin-ppc)
+# check for a case sensitive file system
+ifneq (a,$(shell mkdir -p $(OUT_DIR) ; \
+                echo a > $(OUT_DIR)/casecheck.txt; \
+                    echo B > $(OUT_DIR)/CaseCheck.txt; \
+                cat $(OUT_DIR)/casecheck.txt))
+$(warning ************************************************************)
+$(warning You are building on a case-insensitive filesystem.)
+$(warning Please move your source tree to a case-sensitive filesystem.)
+$(warning ************************************************************)
+$(error Case-insensitive filesystems not supported)
+endif
+endif
+endif
+
+# Make sure that there are no spaces in the absolute path; the
+# build system can't deal with them.
+ifneq ($(words $(shell pwd)),1)
+$(warning ************************************************************)
+$(warning You are building in a directory whose absolute path contains)
+$(warning a space character:)
+$(warning $(space))
+$(warning "$(shell pwd)")
+$(warning $(space))
+$(warning Please move your source tree to a path that does not contain)
+$(warning any spaces.)
+$(warning ************************************************************)
+$(error Directory names containing spaces not supported)
+endif
+
+
+# Check for the correct version of java
+java_version := $(shell java -version 2>&1 | head -n 1 | grep '[ "]1\.6[\. "$$]')
+ifeq ($(strip $(java_version)),)
+$(info ************************************************************)
+$(info You are attempting to build with the incorrect version)
+$(info of java.)
+$(info $(space))
+$(info Your version is: $(shell java -version 2>&1 | head -n 1).)
+$(info The correct version is: 1.6.)
+$(info $(space))
+$(info Please follow the machine setup instructions at)
+$(info $(space)$(space)$(space)$(space)http://source.android.com/source/download.html)
+$(info ************************************************************)
+$(error stop)
+endif
+
+# Check for the correct version of javac
+javac_version := $(shell javac -version 2>&1 | head -n 1 | grep '[ "]1\.6[\. "$$]')
+ifeq ($(strip $(javac_version)),)
+$(info ************************************************************)
+$(info You are attempting to build with the incorrect version)
+$(info of javac.)
+$(info $(space))
+$(info Your version is: $(shell javac -version 2>&1 | head -n 1).)
+$(info The correct version is: 1.6.)
+$(info $(space))
+$(info Please follow the machine setup instructions at)
+$(info $(space)$(space)$(space)$(space)http://source.android.com/source/download.html)
+$(info ************************************************************)
+$(error stop)
+endif
+
+$(shell echo 'VERSIONS_CHECKED := $(VERSION_CHECK_SEQUENCE_NUMBER)' \
+        > $(OUT_DIR)/versions_checked.mk)
+endif
+
+# These are the modifier targets that don't do anything themselves, but
+# change the behavior of the build.
+# (must be defined before including definitions.make)
+INTERNAL_MODIFIER_TARGETS := showcommands checkbuild all
+
+# Bring in standard build system definitions.
+include $(BUILD_SYSTEM)/definitions.mk
+
+# Bring in dex_preopt.mk
+include $(BUILD_SYSTEM)/dex_preopt.mk
+
+ifneq ($(filter eng user userdebug tests,$(MAKECMDGOALS)),)
+$(info ***************************************************************)
+$(info ***************************************************************)
+$(info Don't pass '$(filter eng user userdebug tests,$(MAKECMDGOALS))' on \
+               the make command line.)
+# XXX The single quote on this line fixes gvim's syntax highlighting.
+# Without which, the rest of this file is impossible to read.
+$(info Set TARGET_BUILD_VARIANT in buildspec.mk, or use lunch or)
+$(info choosecombo.)
+$(info ***************************************************************)
+$(info ***************************************************************)
+$(error stopping)
+endif
+
+ifneq ($(filter-out $(INTERNAL_VALID_VARIANTS),$(TARGET_BUILD_VARIANT)),)
+$(info ***************************************************************)
+$(info ***************************************************************)
+$(info Invalid variant: $(TARGET_BUILD_VARIANT)
+$(info Valid values are: $(INTERNAL_VALID_VARIANTS)
+$(info ***************************************************************)
+$(info ***************************************************************)
+$(error stopping)
+endif
+
+###
+### In this section we set up the things that are different
+### between the build variants
+###
+
+is_sdk_build :=
+ifneq ($(filter sdk,$(MAKECMDGOALS)),)
+is_sdk_build := true
+endif
+ifneq ($(filter win_sdk,$(MAKECMDGOALS)),)
+is_sdk_build := true
+endif
+ifneq ($(filter sdk_addon,$(MAKECMDGOALS)),)
+is_sdk_build := true
+endif
+
+
+## user/userdebug ##
+
+user_variant := $(filter userdebug user,$(TARGET_BUILD_VARIANT))
+enable_target_debugging := true
+ifneq (,$(user_variant))
+  # Target is secure in user builds.
+  ADDITIONAL_DEFAULT_PROPERTIES += ro.secure=1
+
+  tags_to_install := user
+  ifeq ($(user_variant),userdebug)
+    # Pick up some extra useful tools
+    tags_to_install += debug
+
+    # Enable Dalvik lock contention logging for userdebug builds.
+    ADDITIONAL_BUILD_PROPERTIES += dalvik.vm.lockprof.threshold=500
+  else
+    # Disable debugging in plain user builds.
+    enable_target_debugging :=
+  endif
+
+  # TODO: Remove this and the corresponding block in
+  # config/product_config.make once host-based Dalvik preoptimization is
+  # working.
+  ifneq (true,$(DISABLE_DEXPREOPT))
+  ifeq ($(HOST_OS)-$(WITH_DEXPREOPT_buildbot),linux-true)
+    WITH_DEXPREOPT := true
+  endif
+  endif
+
+  # Disallow mock locations by default for user builds
+  ADDITIONAL_DEFAULT_PROPERTIES += ro.allow.mock.location=0
+
+else # !user_variant
+  # Turn on checkjni for non-user builds.
+  ADDITIONAL_BUILD_PROPERTIES += ro.kernel.android.checkjni=1
+  # Set device insecure for non-user builds.
+  ADDITIONAL_DEFAULT_PROPERTIES += ro.secure=0
+  # Allow mock locations by default for non user builds
+  ADDITIONAL_DEFAULT_PROPERTIES += ro.allow.mock.location=1
+endif # !user_variant
+
+ifeq (true,$(strip $(enable_target_debugging)))
+  # Target is more debuggable and adbd is on by default
+  ADDITIONAL_DEFAULT_PROPERTIES += ro.debuggable=1 persist.service.adb.enable=1
+  # Include the debugging/testing OTA keys in this build.
+  INCLUDE_TEST_OTA_KEYS := true
+else # !enable_target_debugging
+  # Target is less debuggable and adbd is off by default
+  ADDITIONAL_DEFAULT_PROPERTIES += ro.debuggable=0 persist.service.adb.enable=0
+endif # !enable_target_debugging
+
+## eng ##
+
+ifeq ($(TARGET_BUILD_VARIANT),eng)
+tags_to_install := user debug eng
+  # Don't require the setup wizard on eng builds
+  ADDITIONAL_BUILD_PROPERTIES := $(filter-out ro.setupwizard.mode=%,\
+          $(call collapse-pairs, $(ADDITIONAL_BUILD_PROPERTIES))) \
+          ro.setupwizard.mode=OPTIONAL
+endif
+
+## tests ##
+
+ifeq ($(TARGET_BUILD_VARIANT),tests)
+tags_to_install := user debug eng tests
+endif
+
+## sdk ##
+
+ifdef is_sdk_build
+ifneq ($(words $(filter-out $(INTERNAL_MODIFIER_TARGETS),$(MAKECMDGOALS))),1)
+$(error The 'sdk' target may not be specified with any other targets)
+endif
+
+# TODO: this should be eng I think.  Since the sdk is built from the eng
+# variant.
+tags_to_install := user debug eng
+ADDITIONAL_BUILD_PROPERTIES += xmpp.auto-presence=true
+ADDITIONAL_BUILD_PROPERTIES += ro.config.nocheckin=yes
+else # !sdk
+endif
+
+BUILD_WITHOUT_PV := true
+
+## precise GC ##
+
+ifneq ($(filter dalvik.gc.type-precise,$(PRODUCT_TAGS)),)
+  # Enabling type-precise GC results in larger optimized DEX files.  The
+  # additional storage requirements for ".odex" files can cause /system
+  # to overflow on some devices, so this is configured separately for
+  # each product.
+  ADDITIONAL_BUILD_PROPERTIES += dalvik.vm.dexopt-flags=m=y
+endif
+
+# Install an apns-conf.xml file if one's not already being installed.
+ifeq (,$(filter %:system/etc/apns-conf.xml, $(PRODUCT_COPY_FILES)))
+  PRODUCT_COPY_FILES += \
+        development/data/etc/apns-conf_sdk.xml:system/etc/apns-conf.xml
+  ifeq ($(filter eng tests,$(TARGET_BUILD_VARIANT)),)
+    $(warning implicitly installing apns-conf_sdk.xml)
+  endif
+endif
+# If we're on an eng or tests build, but not on the sdk, and we have
+# a better one, use that instead.
+ifneq ($(filter eng tests,$(TARGET_BUILD_VARIANT)),)
+  ifndef is_sdk_build
+    apns_to_use := $(wildcard vendor/google/etc/apns-conf.xml)
+    ifneq ($(strip $(apns_to_use)),)
+      PRODUCT_COPY_FILES := \
+            $(filter-out %:system/etc/apns-conf.xml,$(PRODUCT_COPY_FILES)) \
+            $(strip $(apns_to_use)):system/etc/apns-conf.xml
+    endif
+  endif
+endif
+
+ADDITIONAL_BUILD_PROPERTIES += net.bt.name=Android
+
+# enable vm tracing in files for now to help track
+# the cause of ANRs in the content process
+ADDITIONAL_BUILD_PROPERTIES += dalvik.vm.stack-trace-file=/data/anr/traces.txt
+
+# ------------------------------------------------------------
+# Define a function that, given a list of module tags, returns
+# non-empty if that module should be installed in /system.
+
+# For most goals, anything not tagged with the "tests" tag should
+# be installed in /system.
+define should-install-to-system
+$(if $(filter tests,$(1)),,true)
+endef
+
+ifdef is_sdk_build
+# For the sdk goal, anything with the "samples" tag should be
+# installed in /data even if that module also has "eng"/"debug"/"user".
+define should-install-to-system
+$(if $(filter samples tests,$(1)),,true)
+endef
+endif
+
+
+# If they only used the modifier goals (showcommands, checkbuild), we'll actually
+# build the default target.
+ifeq ($(filter-out $(INTERNAL_MODIFIER_TARGETS),$(MAKECMDGOALS)),)
+.PHONY: $(INTERNAL_MODIFIER_TARGETS)
+$(INTERNAL_MODIFIER_TARGETS): $(DEFAULT_GOAL)
+endif
+
+# These targets are going to delete stuff, don't bother including
+# the whole directory tree if that's all we're going to do
+ifeq ($(MAKECMDGOALS),clean)
+dont_bother := true
+endif
+ifeq ($(MAKECMDGOALS),clobber)
+dont_bother := true
+endif
+ifeq ($(MAKECMDGOALS),dataclean)
+dont_bother := true
+endif
+ifeq ($(MAKECMDGOALS),installclean)
+dont_bother := true
+endif
+
+# Bring in all modules that need to be built.
+ifneq ($(dont_bother),true)
+
+ifeq ($(HOST_OS)-$(HOST_ARCH),darwin-ppc)
+SDK_ONLY := true
+$(info Building the SDK under darwin-ppc is actually obsolete and unsupported.)
+$(error stop)
+endif
+
+ifeq ($(HOST_OS),windows)
+SDK_ONLY := true
+endif
+
+ifeq ($(SDK_ONLY),true)
+
+# ----- SDK for Windows ------
+# These configure the build targets that are available for the SDK under Windows.
+# The first section defines all the C/C++ tools that can be compiled in C/C++,
+# the second section defines all the Java ones (assuming javac is available.)
+
+subdirs := \
+       prebuilt \
+       build/libs/host \
+       build/tools/zipalign \
+       dalvik/dexdump \
+       dalvik/libdex \
+       dalvik/tools/dmtracedump \
+       dalvik/tools/hprof-conv \
+       development/host \
+       development/tools/etc1tool \
+       development/tools/line_endings \
+       external/easymock \
+       external/expat \
+       external/libpng \
+       external/qemu \
+       external/sqlite/dist \
+       external/zlib \
+       frameworks/base \
+       sdk/emulator/mksdcard \
+       sdk/sdklauncher \
+       system/core/adb \
+       system/core/fastboot \
+       system/core/libcutils \
+       system/core/liblog \
+       system/core/libzipfile
+
+# The following can only be built if "javac" is available.
+# This check is used when building parts of the SDK under Cygwin.
+ifneq (,$(shell which javac 2>/dev/null))
+subdirs += \
+       build/tools/signapk \
+       dalvik/dx \
+       libcore \
+       sdk/archquery \
+       sdk/androidprefs \
+       sdk/apkbuilder \
+       sdk/common \
+       sdk/ddms \
+       sdk/hierarchyviewer2 \
+       sdk/ide_common \
+       sdk/jarutils \
+       sdk/layoutlib_api \
+       sdk/layoutopt \
+       sdk/ninepatch \
+       sdk/sdkstats \
+       sdk/sdkmanager \
+       development/apps \
+       development/tools/mkstubs \
+       packages
+else
+$(warning SDK_ONLY: javac not available.)
+endif
+
+# Exclude tools/acp when cross-compiling windows under linux
+ifeq ($(findstring Linux,$(UNAME)),)
+subdirs += build/tools/acp
+endif
+
+else   # !SDK_ONLY
+ifeq ($(BUILD_TINY_ANDROID), true)
+
+# TINY_ANDROID is a super-minimal build configuration, handy for board 
+# bringup and very low level debugging
+
+subdirs := \
+       bionic \
+       system/core \
+       build/libs \
+       build/target \
+       build/tools/acp \
+       build/tools/apriori \
+       build/tools/kcm \
+       build/tools/soslim \
+       external/elfcopy \
+       external/elfutils \
+       external/yaffs2 \
+       external/zlib
+else   # !BUILD_TINY_ANDROID
+
+#
+# Typical build; include any Android.mk files we can find.
+#
+subdirs := $(TOP)
+
+FULL_BUILD := true
+
+endif  # !BUILD_TINY_ANDROID
+
+endif  # !SDK_ONLY
+
+ifneq ($(ONE_SHOT_MAKEFILE),)
+# We've probably been invoked by the "mm" shell function
+# with a subdirectory's makefile.
+include $(ONE_SHOT_MAKEFILE)
+# Change CUSTOM_MODULES to include only modules that were
+# defined by this makefile; this will install all of those
+# modules as a side-effect.  Do this after including ONE_SHOT_MAKEFILE
+# so that the modules will be installed in the same place they
+# would have been with a normal make.
+CUSTOM_MODULES := $(sort $(call get-tagged-modules,$(ALL_MODULE_TAGS)))
+FULL_BUILD :=
+# Stub out the notice targets, which probably aren't defined
+# when using ONE_SHOT_MAKEFILE.
+NOTICE-HOST-%: ;
+NOTICE-TARGET-%: ;
+
+else # ONE_SHOT_MAKEFILE
+
+#
+# Include all of the makefiles in the system
+#
+
+# Can't use first-makefiles-under here because
+# --mindepth=2 makes the prunes not work.
+subdir_makefiles := \
+       $(shell build/tools/findleaves.py --prune=out --prune=.repo --prune=.git $(subdirs) Android.mk)
+
+include $(subdir_makefiles)
+endif # ONE_SHOT_MAKEFILE
+
+# -------------------------------------------------------------------
+# All module makefiles have been included at this point.
+# -------------------------------------------------------------------
+
+# -------------------------------------------------------------------
+# Include any makefiles that must happen after the module makefiles
+# have been included.
+# TODO: have these files register themselves via a global var rather
+# than hard-coding the list here.
+ifdef FULL_BUILD
+  # Only include this during a full build, otherwise we can't be
+  # guaranteed that any policies were included.
+  -include frameworks/policies/base/PolicyConfig.mk
+endif
+
+# -------------------------------------------------------------------
+# Fix up CUSTOM_MODULES to refer to installed files rather than
+# just bare module names.  Leave unknown modules alone in case
+# they're actually full paths to a particular file.
+known_custom_modules := $(filter $(ALL_MODULES),$(CUSTOM_MODULES))
+unknown_custom_modules := $(filter-out $(ALL_MODULES),$(CUSTOM_MODULES))
+CUSTOM_MODULES := \
+       $(call module-installed-files,$(known_custom_modules)) \
+       $(unknown_custom_modules)
+
+# -------------------------------------------------------------------
+# Define dependencies for modules that require other modules.
+# This can only happen now, after we've read in all module makefiles.
+#
+# TODO: deal with the fact that a bare module name isn't
+# unambiguous enough.  Maybe declare short targets like
+# APPS:Quake or HOST:SHARED_LIBRARIES:libutils.
+# BUG: the system image won't know to depend on modules that are
+# brought in as requirements of other modules.
+define add-required-deps
+$(1): $(2)
+endef
+$(foreach m,$(ALL_MODULES), \
+  $(eval r := $(ALL_MODULES.$(m).REQUIRED)) \
+  $(if $(r), \
+    $(eval r := $(call module-installed-files,$(r))) \
+    $(eval $(call add-required-deps,$(ALL_MODULES.$(m).INSTALLED),$(r))) \
+   ) \
+ )
+m :=
+r :=
+add-required-deps :=
+
+# -------------------------------------------------------------------
+# Figure out our module sets.
+
+# Of the modules defined by the component makefiles,
+# determine what we actually want to build.
+Default_MODULES := $(sort $(ALL_DEFAULT_INSTALLED_MODULES) \
+                          $(CUSTOM_MODULES))
+# TODO: Remove the 3 places in the tree that use
+# ALL_DEFAULT_INSTALLED_MODULES and get rid of it from this list.
+
+ifdef FULL_BUILD
+  # The base list of modules to build for this product is specified
+  # by the appropriate product definition file, which was included
+  # by product_config.make.
+  user_PACKAGES := $(call module-installed-files, \
+                       $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGES))
+  ifeq (0,1)
+    $(info user packages for $(TARGET_DEVICE) ($(INTERNAL_PRODUCT)):)
+    $(foreach p,$(user_PACKAGES),$(info :   $(p)))
+    $(error done)
+  endif
+else
+  # We're not doing a full build, and are probably only including
+  # a subset of the module makefiles.  Don't try to build any modules
+  # requested by the product, because we probably won't have rules
+  # to build them.
+  user_PACKAGES :=
+endif
+# Use tags to get the non-APPS user modules.  Use the product
+# definition files to get the APPS user modules.
+user_MODULES := $(sort $(call get-tagged-modules,user shell_$(TARGET_SHELL)))
+user_MODULES := $(user_MODULES) $(user_PACKAGES)
+
+eng_MODULES := $(sort $(call get-tagged-modules,eng))
+debug_MODULES := $(sort $(call get-tagged-modules,debug))
+tests_MODULES := $(sort $(call get-tagged-modules,tests))
+
+ifeq ($(strip $(tags_to_install)),)
+$(error ASSERTION FAILED: tags_to_install should not be empty)
+endif
+modules_to_install := $(sort $(Default_MODULES) \
+          $(foreach tag,$(tags_to_install),$($(tag)_MODULES)))
+
+# Some packages may override others using LOCAL_OVERRIDES_PACKAGES.
+# Filter out (do not install) any overridden packages.
+overridden_packages := $(call get-package-overrides,$(modules_to_install))
+ifdef overridden_packages
+#  old_modules_to_install := $(modules_to_install)
+  modules_to_install := \
+      $(filter-out $(foreach p,$(overridden_packages),$(p) %/$(p).apk), \
+          $(modules_to_install))
+endif
+#$(error filtered out
+#           $(filter-out $(modules_to_install),$(old_modules_to_install)))
+
+# Don't include any GNU targets in the SDK.  It's ok (and necessary)
+# to build the host tools, but nothing that's going to be installed
+# on the target (including static libraries).
+ifdef is_sdk_build
+  target_gnu_MODULES := \
+              $(filter \
+                      $(TARGET_OUT_INTERMEDIATES)/% \
+                      $(TARGET_OUT)/% \
+                      $(TARGET_OUT_DATA)/%, \
+                              $(sort $(call get-tagged-modules,gnu)))
+  $(info Removing from sdk:)$(foreach d,$(target_gnu_MODULES),$(info : $(d)))
+  modules_to_install := \
+              $(filter-out $(target_gnu_MODULES),$(modules_to_install))
+endif
+
+
+# build/core/Makefile contains extra stuff that we don't want to pollute this
+# top-level makefile with.  It expects that ALL_DEFAULT_INSTALLED_MODULES
+# contains everything that's built during the current make, but it also further
+# extends ALL_DEFAULT_INSTALLED_MODULES.
+ALL_DEFAULT_INSTALLED_MODULES := $(modules_to_install)
+include $(BUILD_SYSTEM)/Makefile
+modules_to_install := $(sort $(ALL_DEFAULT_INSTALLED_MODULES))
+ALL_DEFAULT_INSTALLED_MODULES :=
+
+endif # dont_bother
+
+# These are additional goals that we build, in order to make sure that there
+# is as little code as possible in the tree that doesn't build.
+modules_to_check := $(foreach m,$(ALL_MODULES),$(ALL_MODULES.$(m).CHECKED))
+
+# If you would like to build all goals, and not skip any intermediate
+# steps, you can pass the "all" modifier goal on the commandline.
+ifneq ($(filter all,$(MAKECMDGOALS)),)
+modules_to_check += $(foreach m,$(ALL_MODULES),$(ALL_MODULES.$(m).BUILT))
+endif
+
+# for easier debugging
+modules_to_check := $(sort $(modules_to_check))
+#$(error modules_to_check $(modules_to_check))
+
+# -------------------------------------------------------------------
+# This is used to to get the ordering right, you can also use these,
+# but they're considered undocumented, so don't complain if their
+# behavior changes.
+.PHONY: prebuilt
+prebuilt: $(ALL_PREBUILT)
+
+# An internal target that depends on all copied headers
+# (see copy_headers.make).  Other targets that need the
+# headers to be copied first can depend on this target.
+.PHONY: all_copied_headers
+all_copied_headers: ;
+
+$(ALL_C_CPP_ETC_OBJECTS): | all_copied_headers
+
+# All the droid stuff, in directories
+.PHONY: files
+files: prebuilt \
+        $(modules_to_install) \
+        $(modules_to_check) \
+        $(INSTALLED_ANDROID_INFO_TXT_TARGET)
+
+# -------------------------------------------------------------------
+
+.PHONY: checkbuild
+checkbuild: $(modules_to_check)
+
+.PHONY: ramdisk
+ramdisk: $(INSTALLED_RAMDISK_TARGET)
+
+.PHONY: systemtarball
+systemtarball: $(INSTALLED_SYSTEMTARBALL_TARGET)
+
+.PHONY: boottarball
+boottarball: $(INSTALLED_BOOTTARBALL_TARGET)
+
+.PHONY: userdataimage
+userdataimage: $(INSTALLED_USERDATAIMAGE_TARGET)
+
+.PHONY: userdatatarball
+userdatatarball: $(INSTALLED_USERDATATARBALL_TARGET)
+
+.PHONY: bootimage
+bootimage: $(INSTALLED_BOOTIMAGE_TARGET)
+
+ifeq ($(BUILD_TINY_ANDROID), true)
+INSTALLED_RECOVERYIMAGE_TARGET :=
+endif
+
+# Build files and then package it into the rom formats
+.PHONY: droidcore
+droidcore: files \
+       systemimage \
+       $(INSTALLED_BOOTIMAGE_TARGET) \
+       $(INSTALLED_RECOVERYIMAGE_TARGET) \
+       $(INSTALLED_USERDATAIMAGE_TARGET) \
+       $(INSTALLED_FILES_FILE)
+
+ifeq ($(EMMA_INSTRUMENT),true)
+  $(call dist-for-goals, droid, $(EMMA_META_ZIP))
+endif
+
+# dist_libraries only for putting your library into the dist directory with a full build.
+.PHONY: dist_libraries
+
+ifneq ($(TARGET_BUILD_APPS),)
+  # If this build is just for apps, only build apps and not the full system by default.
+
+  unbundled_build_modules :=
+  ifneq ($(filter all,$(TARGET_BUILD_APPS)),)
+    # If they used the magic goal "all" then build all apps in the source tree.
+    unbundled_build_modules := $(foreach m,$(sort $(ALL_MODULES)),$(if $(filter APPS,$(ALL_MODULES.$(m).CLASS)),$(m)))
+  else
+    unbundled_build_modules := $(TARGET_BUILD_APPS)
+  endif
+
+  # dist the unbundled app.
+  $(call dist-for-goals,apps_only, \
+    $(foreach m,$(unbundled_build_modules),$(ALL_MODULES.$(m).INSTALLED)) \
+  )
+
+.PHONY: apps_only
+apps_only: $(unbundled_build_modules)
+
+droid: apps_only
+
+else # TARGET_BUILD_APPS
+  $(call dist-for-goals, droidcore, \
+    $(INTERNAL_UPDATE_PACKAGE_TARGET) \
+    $(INTERNAL_OTA_PACKAGE_TARGET) \
+    $(SYMBOLS_ZIP) \
+    $(APPS_ZIP) \
+    $(INTERNAL_EMULATOR_PACKAGE_TARGET) \
+    $(PACKAGE_STATS_FILE) \
+    $(INSTALLED_FILES_FILE) \
+    $(INSTALLED_BUILD_PROP_TARGET) \
+    $(BUILT_TARGET_FILES_PACKAGE) \
+    $(INSTALLED_ANDROID_INFO_TXT_TARGET) \
+    $(INSTALLED_RAMDISK_TARGET) \
+   )
+
+# Building a full system-- the default is to build droidcore
+droid: droidcore dist_libraries
+
+endif
+
+
+.PHONY: droid tests
+tests: droidcore
+
+# phony target that include any targets in $(ALL_MODULES)
+.PHONY: all_modules
+all_modules: $(ALL_MODULES)
+
+.PHONY: docs
+docs: $(ALL_DOCS)
+
+.PHONY: sdk
+ALL_SDK_TARGETS := $(INTERNAL_SDK_TARGET)
+sdk: $(ALL_SDK_TARGETS)
+$(call dist-for-goals,sdk, \
+       $(ALL_SDK_TARGETS) \
+       $(SYMBOLS_ZIP) \
+ )
+
+.PHONY: findbugs
+findbugs: $(INTERNAL_FINDBUGS_HTML_TARGET) $(INTERNAL_FINDBUGS_XML_TARGET)
+
+.PHONY: clean
+clean:
+       @rm -rf $(OUT_DIR)
+       @echo "Entire build directory removed."
+
+.PHONY: clobber
+clobber: clean
+
+# The rules for dataclean and installclean are defined in cleanbuild.mk.
+
+#xxx scrape this from ALL_MODULE_NAME_TAGS
+.PHONY: modules
+modules:
+       @echo "Available sub-modules:"
+       @echo "$(call module-names-for-tag-list,$(ALL_MODULE_TAGS))" | \
+             tr -s ' ' '\n' | sort -u | $(COLUMN)
+
+.PHONY: showcommands
+showcommands:
+       @echo >/dev/null
diff --git a/build/core/multi_prebuilt.mk b/build/core/multi_prebuilt.mk
new file mode 100644 (file)
index 0000000..7602673
--- /dev/null
@@ -0,0 +1,120 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Save these before they get cleared by CLEAR_VARS.
+prebuilt_static_libs := $(filter %.a,$(LOCAL_PREBUILT_LIBS))
+prebuilt_shared_libs := $(filter-out %.a,$(LOCAL_PREBUILT_LIBS))
+prebuilt_executables := $(LOCAL_PREBUILT_EXECUTABLES)
+prebuilt_java_libraries := $(LOCAL_PREBUILT_JAVA_LIBRARIES)
+prebuilt_static_java_libraries := $(LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES)
+prebuilt_is_host := $(LOCAL_IS_HOST_MODULE)
+prebuilt_module_tags := $(LOCAL_MODULE_TAGS)
+
+
+ifndef multi_prebuilt_once
+multi_prebuilt_once := true
+
+# $(1): file list
+# $(2): IS_HOST_MODULE
+# $(3): MODULE_CLASS
+# $(4): MODULE_TAGS
+# $(5): OVERRIDE_BUILT_MODULE_PATH
+# $(6): UNINSTALLABLE_MODULE
+# $(7): BUILT_MODULE_STEM
+#
+# Elements in the file list may be bare filenames,
+# or of the form "<modulename>:<filename>".
+# If the module name is not specified, the module
+# name will be the filename with the suffix removed.
+#
+define auto-prebuilt-boilerplate
+$(if $(filter %: :%,$(1)), \
+  $(error $(LOCAL_PATH): Leading or trailing colons in "$(1)")) \
+$(foreach t,$(1), \
+  $(eval include $(CLEAR_VARS)) \
+  $(eval LOCAL_IS_HOST_MODULE := $(2)) \
+  $(eval LOCAL_MODULE_CLASS := $(3)) \
+  $(eval LOCAL_MODULE_TAGS := $(4)) \
+  $(eval OVERRIDE_BUILT_MODULE_PATH := $(5)) \
+  $(eval LOCAL_UNINSTALLABLE_MODULE := $(6)) \
+  $(eval tw := $(subst :, ,$(strip $(t)))) \
+  $(if $(word 3,$(tw)),$(error $(LOCAL_PATH): Bad prebuilt filename '$(t)')) \
+  $(if $(word 2,$(tw)), \
+    $(eval LOCAL_MODULE := $(word 1,$(tw))) \
+    $(eval LOCAL_SRC_FILES := $(word 2,$(tw))) \
+   , \
+    $(eval LOCAL_MODULE := $(basename $(notdir $(t)))) \
+    $(eval LOCAL_SRC_FILES := $(t)) \
+   ) \
+  $(if $(7), \
+    $(eval LOCAL_BUILT_MODULE_STEM := $(7)) \
+   , \
+    $(eval LOCAL_BUILT_MODULE_STEM := $(notdir $(LOCAL_SRC_FILES))) \
+   ) \
+  $(eval LOCAL_MODULE_SUFFIX := $(suffix $(LOCAL_SRC_FILES))) \
+  $(eval include $(BUILD_PREBUILT)) \
+ )
+endef
+
+endif # multi_prebuilt_once
+
+
+$(call auto-prebuilt-boilerplate, \
+    $(prebuilt_static_libs), \
+    $(prebuilt_is_host), \
+    STATIC_LIBRARIES, \
+    $(prebuilt_module_tags), \
+    , \
+    true)
+
+$(call auto-prebuilt-boilerplate, \
+    $(prebuilt_shared_libs), \
+    $(prebuilt_is_host), \
+    SHARED_LIBRARIES, \
+    $(prebuilt_module_tags), \
+    $($(if $(prebuilt_is_host),HOST,TARGET)_OUT_INTERMEDIATE_LIBRARIES))
+
+$(call auto-prebuilt-boilerplate, \
+    $(prebuilt_executables), \
+    $(prebuilt_is_host), \
+    EXECUTABLES, \
+    $(prebuilt_module_tags))
+
+$(call auto-prebuilt-boilerplate, \
+    $(prebuilt_java_libraries), \
+    $(prebuilt_is_host), \
+    JAVA_LIBRARIES, \
+    $(prebuilt_module_tags), \
+    , \
+    , \
+    javalib.jar)
+
+$(call auto-prebuilt-boilerplate, \
+    $(prebuilt_static_java_libraries), \
+    $(prebuilt_is_host), \
+    JAVA_LIBRARIES, \
+    $(prebuilt_module_tags), \
+    , \
+    true, \
+    javalib.jar)
+
+prebuilt_static_libs :=
+prebuilt_shared_libs :=
+prebuilt_executables :=
+prebuilt_java_libraries :=
+prebuilt_static_java_libraries :=
+prebuilt_is_host :=
+prebuilt_module_tags :=
diff --git a/build/core/node_fns.mk b/build/core/node_fns.mk
new file mode 100644 (file)
index 0000000..38ecea7
--- /dev/null
@@ -0,0 +1,258 @@
+#
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Clears a list of variables using ":=".
+#
+# E.g.,
+#   $(call clear-var-list,A B C)
+# would be the same as:
+#   A :=
+#   B :=
+#   C :=
+#
+# $(1): list of variable names to clear
+#
+define clear-var-list
+$(foreach v,$(1),$(eval $(v):=))
+endef
+
+#
+# Copies a list of variables into another list of variables.
+# The target list is the same as the source list, but has
+# a dotted prefix affixed to it.
+#
+# E.g.,
+#   $(call copy-var-list, PREFIX, A B)
+# would be the same as:
+#   PREFIX.A := $(A)
+#   PREFIX.B := $(B)
+#
+# $(1): destination prefix
+# $(2): list of variable names to copy
+#
+define copy-var-list
+$(foreach v,$(2),$(eval $(strip $(1)).$(v):=$($(v))))
+endef
+
+#
+# Moves a list of variables into another list of variables.
+# The variable names differ by a prefix.  After moving, the
+# source variable is cleared.
+#
+# NOTE: Spaces are not allowed around the prefixes.
+#
+# E.g.,
+#   $(call move-var-list,SRC,DST,A B)
+# would be the same as:
+#   DST.A := $(SRC.A)
+#   SRC.A :=
+#   DST.B := $(SRC.B)
+#   SRC.B :=
+#
+# $(1): source prefix
+# $(2): destination prefix
+# $(3): list of variable names to move
+#
+define move-var-list
+$(foreach v,$(3), \
+  $(eval $(2).$(v) := $($(1).$(v))) \
+  $(eval $(1).$(v) :=) \
+ )
+endef
+
+#
+# $(1): haystack
+# $(2): needle
+#
+# Guarantees that needle appears at most once in haystack,
+# without changing the order of other elements in haystack.
+# If needle appears multiple times, only the first occurrance
+# will survive.
+#
+# How it works:
+#
+# - Stick everything in haystack into a single word,
+#   with "|||" separating the words.
+# - Replace occurrances of "|||$(needle)|||" with "||| |||",
+#   breaking haystack back into multiple words, with spaces
+#   where needle appeared.
+# - Add needle between the first and second words of haystack.
+# - Replace "|||" with spaces, breaking haystack back into
+#   individual words.
+#
+empty :=
+space := $(empty) $(empty)
+define uniq-word
+$(strip \
+  $(if $(filter $(2),$(1)), \
+    $(eval h := |||$(subst $(space),|||,$(strip $(1)))|||) \
+    $(eval h := $(subst |||$(strip $(2))|||,|||$(space)|||,$(h))) \
+    $(eval h := $(word 1,$(h)) $(2) $(wordlist 2,9999,$(h))) \
+    $(subst |||,$(space),$(h)) \
+   , \
+    $(1) \
+ ))
+endef
+
+INHERIT_TAG := @inherit:
+
+#
+# Walks through the list of variables, each qualified by the prefix,
+# and finds instances of words beginning with INHERIT_TAG.  Scrape
+# off INHERIT_TAG from each matching word, and return the sorted,
+# unique set of those words.
+#
+# E.g., given
+#   PREFIX.A := A $(INHERIT_TAG)aaa B C
+#   PREFIX.B := B $(INHERIT_TAG)aaa C $(INHERIT_TAG)bbb D E
+# Then
+#   $(call get-inherited-nodes,PREFIX,A B)
+# returns
+#   aaa bbb
+#
+# $(1): variable prefix
+# $(2): list of variables to check
+#
+define get-inherited-nodes
+$(sort \
+  $(subst $(INHERIT_TAG),, \
+    $(filter $(INHERIT_TAG)%, \
+      $(foreach v,$(2),$($(1).$(v))) \
+ )))
+endef
+
+#
+# for each variable ( (prefix + name) * vars ):
+#   get list of inherited words; if not empty:
+#     for each inherit:
+#       replace the first occurrence with (prefix + inherited + var)
+#       clear the source var so we can't inherit the value twice
+#
+# $(1): context prefix
+# $(2): name of this node
+# $(3): list of variable names
+#
+define _expand-inherited-values
+  $(foreach v,$(3), \
+    $(eval ### "Shorthand for the name of the target variable") \
+    $(eval _eiv_tv := $(1).$(2).$(v)) \
+    $(eval ### "Get the list of nodes that this variable inherits") \
+    $(eval _eiv_i := \
+        $(sort \
+            $(patsubst $(INHERIT_TAG)%,%, \
+                $(filter $(INHERIT_TAG)%, $($(_eiv_tv)) \
+     )))) \
+    $(foreach i,$(_eiv_i), \
+      $(eval ### "Make sure that this inherit appears only once") \
+      $(eval $(_eiv_tv) := \
+          $(call uniq-word,$($(_eiv_tv)),$(INHERIT_TAG)$(i))) \
+      $(eval ### "Expand the inherit tag") \
+      $(eval $(_eiv_tv) := \
+          $(strip \
+              $(patsubst $(INHERIT_TAG)$(i),$($(1).$(i).$(v)), \
+                  $($(_eiv_tv))))) \
+      $(eval ### "Clear the child so DAGs don't create duplicate entries" ) \
+      $(eval $(1).$(i).$(v) :=) \
+      $(eval ### "If we just inherited ourselves, it's a cycle.") \
+      $(if $(filter $(INHERIT_TAG)$(2),$($(_eiv_tv))), \
+        $(warning Cycle detected between "$(2)" and "$(i)" for context "$(1)") \
+        $(error import of "$(2)" failed) \
+      ) \
+     ) \
+   ) \
+   $(eval _eiv_tv :=) \
+   $(eval _eiv_i :=)
+endef
+
+#
+# $(1): context prefix
+# $(2): makefile representing this node
+# $(3): list of node variable names
+#
+# _include_stack contains the list of included files, with the most recent files first.
+define _import-node
+  $(eval _include_stack := $(2) $$(_include_stack))
+  $(call clear-var-list, $(3))
+  $(eval LOCAL_PATH := $(patsubst %/,%,$(dir $(2))))
+  $(eval MAKEFILE_LIST :=)
+  $(eval include $(2))
+  $(eval _included := $(filter-out $(2),$(MAKEFILE_LIST)))
+  $(eval MAKEFILE_LIST :=)
+  $(eval LOCAL_PATH :=)
+  $(call copy-var-list, $(1).$(2), $(3))
+  $(call clear-var-list, $(3))
+
+  $(eval $(1).$(2).inherited := \
+      $(call get-inherited-nodes,$(1).$(2),$(3)))
+  $(call _import-nodes-inner,$(1),$($(1).$(2).inherited),$(3))
+
+  $(call _expand-inherited-values,$(1),$(2),$(3))
+
+  $(eval $(1).$(2).inherited :=)
+  $(eval _include_stack := $(wordlist 2,9999,$$(_include_stack)))
+endef
+
+#
+# This will generate a warning for _included above
+#  $(if $(_included), \
+#      $(eval $(warning product spec file: $(2)))\
+#      $(foreach _inc,$(_included),$(eval $(warning $(space)$(space)$(space)includes: $(_inc)))),)
+#
+
+#
+# $(1): context prefix
+# $(2): list of makefiles representing nodes to import
+# $(3): list of node variable names
+#
+#TODO: Make the "does not exist" message more helpful;
+#      should print out the name of the file trying to include it.
+define _import-nodes-inner
+  $(foreach _in,$(2), \
+    $(if $(wildcard $(_in)), \
+      $(if $($(1).$(_in).seen), \
+        $(eval ### "skipping already-imported $(_in)") \
+       , \
+        $(eval $(1).$(_in).seen := true) \
+        $(call _import-node,$(1),$(strip $(_in)),$(3)) \
+       ) \
+     , \
+      $(error $(1): "$(_in)" does not exist) \
+     ) \
+   )
+endef
+
+#
+# $(1): output list variable name, like "PRODUCTS" or "DEVICES"
+# $(2): list of makefiles representing nodes to import
+# $(3): list of node variable names
+#
+define import-nodes
+$(if \
+  $(foreach _in,$(2), \
+    $(eval _node_import_context := _nic.$(1).[[$(_in)]]) \
+    $(if $(_include_stack),$(eval $(error ASSERTION FAILED: _include_stack \
+                should be empty here: $(_include_stack))),) \
+    $(eval _include_stack := ) \
+    $(call _import-nodes-inner,$(_node_import_context),$(_in),$(3)) \
+    $(call move-var-list,$(_node_import_context).$(_in),$(1).$(_in),$(3)) \
+    $(eval _node_import_context :=) \
+    $(eval $(1) := $($(1)) $(_in)) \
+    $(if $(_include_stack),$(eval $(error ASSERTION FAILED: _include_stack \
+                should be empty here: $(_include_stack))),) \
+   ) \
+,)
+endef
diff --git a/build/core/notice_files.mk b/build/core/notice_files.mk
new file mode 100644 (file)
index 0000000..fd76d51
--- /dev/null
@@ -0,0 +1,72 @@
+###########################################################
+## Track NOTICE files
+###########################################################
+
+notice_file:=$(shell find $(LOCAL_PATH) -maxdepth 1 -name NOTICE)
+
+ifneq ($(strip $(notice_file)),)
+
+# This relies on the name of the directory in PRODUCT_OUT matching where
+# it's installed on the target - i.e. system, data, etc.  This does
+# not work for root and isn't exact, but it's probably good enough for
+# compliance.
+# Includes the leading slash
+ifdef LOCAL_INSTALLED_MODULE
+  module_installed_filename := $(patsubst $(PRODUCT_OUT)%,%,$(LOCAL_INSTALLED_MODULE))
+else
+  # This module isn't installable
+  ifeq ($(LOCAL_MODULE_CLASS),STATIC_LIBRARIES)
+    # Stick the static libraries with the dynamic libraries.
+    # We can't use xxx_OUT_STATIC_LIBRARIES because it points into
+    # device-obj or host-obj.
+    module_installed_filename := \
+        $(patsubst $(PRODUCT_OUT)%,%,$($(my_prefix)OUT_SHARED_LIBRARIES))/$(notdir $(LOCAL_BUILT_MODULE))
+  else
+    ifeq ($(LOCAL_MODULE_CLASS),JAVA_LIBRARIES)
+      # Stick the static java libraries with the regular java libraries.
+      module_leaf := $(notdir $(LOCAL_BUILT_MODULE))
+      # javalib.jar is the default name for the build module (and isn't meaningful)
+      # If that's what we have, substitute the module name instead.  These files
+      # aren't included on the device, so this name is synthetic anyway.
+      ifeq ($(module_leaf),javalib.jar)
+        module_leaf := $(LOCAL_MODULE).jar
+      endif
+      module_installed_filename := \
+          $(patsubst $(PRODUCT_OUT)%,%,$($(my_prefix)OUT_JAVA_LIBRARIES))/$(module_leaf)
+    else
+      $(error Cannot determine where to install NOTICE file for $(LOCAL_MODULE))
+    endif # JAVA_LIBRARIES
+  endif # STATIC_LIBRARIES
+endif
+
+# In case it's actually a host file
+module_installed_filename := $(patsubst $(HOST_OUT)%,%,$(module_installed_filename))
+
+installed_notice_file := $($(my_prefix)OUT_NOTICE_FILES)/src/$(module_installed_filename).txt
+
+$(installed_notice_file): PRIVATE_INSTALLED_MODULE := $(module_installed_filename)
+
+$(installed_notice_file): $(notice_file)
+       @echo Notice file: $< -- $@
+       $(hide) mkdir -p $(dir $@)
+       $(hide) cat $< >> $@
+
+ifdef LOCAL_INSTALLED_MODULE
+# Make LOCAL_INSTALLED_MODULE depend on NOTICE files if they exist
+# libraries so they get installed along with it.  Make it an order-only
+# dependency so we don't re-install a module when the NOTICE changes.
+$(LOCAL_INSTALLED_MODULE): | $(installed_notice_file)
+endif
+
+else
+# NOTICE file does not exist
+installed_notice_file :=
+endif
+
+# Create a predictable, phony target to build this notice file.
+# Define it even if the notice file doesn't exist so that other
+# modules can depend on it.
+notice_target := NOTICE-$(if \
+    $(LOCAL_IS_HOST_MODULE),HOST,TARGET)-$(LOCAL_MODULE_CLASS)-$(LOCAL_MODULE)
+.PHONY: $(notice_target)
+$(notice_target): $(installed_notice_file)
diff --git a/build/core/package.mk b/build/core/package.mk
new file mode 100644 (file)
index 0000000..6834995
--- /dev/null
@@ -0,0 +1,362 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+###########################################################
+## Standard rules for building an application package.
+##
+## Additional inputs from base_rules.make:
+## LOCAL_PACKAGE_NAME: The name of the package; the directory
+##             will be called this.
+##
+## MODULE, MODULE_PATH, and MODULE_SUFFIX will
+## be set for you.
+###########################################################
+
+
+# If this makefile is being read from within an inheritance,
+# use the new values.
+skip_definition:=
+ifdef LOCAL_PACKAGE_OVERRIDES
+  package_overridden := $(call set-inherited-package-variables)
+  ifeq ($(strip $(package_overridden)),)
+    skip_definition := true
+  endif
+endif
+
+ifndef skip_definition
+
+LOCAL_PACKAGE_NAME := $(strip $(LOCAL_PACKAGE_NAME))
+ifeq ($(LOCAL_PACKAGE_NAME),)
+$(error $(LOCAL_PATH): Package modules must define LOCAL_PACKAGE_NAME)
+endif
+
+ifneq ($(strip $(LOCAL_MODULE_SUFFIX)),)
+$(error $(LOCAL_PATH): Package modules may not define LOCAL_MODULE_SUFFIX)
+endif
+LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
+
+ifneq ($(strip $(LOCAL_MODULE)),)
+$(error $(LOCAL_PATH): Package modules may not define LOCAL_MODULE)
+endif
+LOCAL_MODULE := $(LOCAL_PACKAGE_NAME)
+
+# Android packages should use Android resources or assets.
+ifneq (,$(LOCAL_JAVA_RESOURCE_DIRS))
+$(error $(LOCAL_PATH): Package modules may not set LOCAL_JAVA_RESOURCE_DIRS)
+endif
+ifneq (,$(LOCAL_JAVA_RESOURCE_FILES))
+$(error $(LOCAL_PATH): Package modules may not set LOCAL_JAVA_RESOURCE_FILES)
+endif
+
+ifeq ($(strip $(LOCAL_MANIFEST_FILE)),)
+LOCAL_MANIFEST_FILE := AndroidManifest.xml
+endif
+
+ifneq ($(strip $(LOCAL_MODULE_CLASS)),)
+$(error $(LOCAL_PATH): Package modules may not set LOCAL_MODULE_CLASS)
+endif
+LOCAL_MODULE_CLASS := APPS
+
+# Package LOCAL_MODULE_TAGS default to optional
+LOCAL_MODULE_TAGS := $(strip $(LOCAL_MODULE_TAGS))
+ifeq ($(LOCAL_MODULE_TAGS),)
+LOCAL_MODULE_TAGS := optional
+endif
+
+#$(warning $(LOCAL_PATH) $(LOCAL_PACKAGE_NAME) $(sort $(LOCAL_MODULE_TAGS)))
+
+ifeq ($(filter tests, $(LOCAL_MODULE_TAGS)),)
+# Force localization check if it's not tagged as tests.
+LOCAL_AAPT_FLAGS := $(LOCAL_AAPT_FLAGS) -z
+endif
+
+ifeq (,$(LOCAL_ASSET_DIR))
+LOCAL_ASSET_DIR := $(LOCAL_PATH)/assets
+endif
+
+ifeq (,$(LOCAL_RESOURCE_DIR))
+  LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+endif
+LOCAL_RESOURCE_DIR := \
+  $(wildcard $(foreach dir, $(PRODUCT_PACKAGE_OVERLAYS), \
+    $(addprefix $(dir)/, $(LOCAL_RESOURCE_DIR)))) \
+  $(wildcard $(foreach dir, $(DEVICE_PACKAGE_OVERLAYS), \
+    $(addprefix $(dir)/, $(LOCAL_RESOURCE_DIR)))) \
+  $(LOCAL_RESOURCE_DIR)
+
+# this is an app, so add the system libraries to the search path
+LOCAL_AIDL_INCLUDES += $(FRAMEWORKS_BASE_JAVA_SRC_DIRS)
+
+#$(warning Finding assets for $(LOCAL_ASSET_DIR))
+
+all_assets := $(call find-subdir-assets,$(LOCAL_ASSET_DIR))
+all_assets := $(addprefix $(LOCAL_ASSET_DIR)/,$(patsubst assets/%,%,$(all_assets)))
+
+all_resources := $(strip \
+    $(foreach dir, $(LOCAL_RESOURCE_DIR), \
+      $(addprefix $(dir)/, \
+        $(patsubst res/%,%, \
+          $(call find-subdir-assets,$(dir)) \
+         ) \
+       ) \
+     ))
+
+all_res_assets := $(strip $(all_assets) $(all_resources))
+
+package_expected_intermediates_COMMON := $(call local-intermediates-dir,COMMON)
+# If no assets or resources were found, clear the directory variables so
+# we don't try to build them.
+ifeq (,$(all_assets))
+LOCAL_ASSET_DIR:=
+endif
+ifeq (,$(all_resources))
+LOCAL_RESOURCE_DIR:=
+R_file_stamp :=
+else
+# Make sure that R_file_stamp inherits the proper PRIVATE vars.
+# If R.stamp moves, be sure to update the framework makefile,
+# which has intimate knowledge of its location.
+R_file_stamp := $(package_expected_intermediates_COMMON)/src/R.stamp
+LOCAL_INTERMEDIATE_TARGETS += $(R_file_stamp)
+endif
+
+LOCAL_BUILT_MODULE_STEM := package.apk
+
+LOCAL_PROGUARD_ENABLED:=$(strip $(LOCAL_PROGUARD_ENABLED))
+ifndef LOCAL_PROGUARD_ENABLED
+ifneq ($(filter user userdebug, $(TARGET_BUILD_VARIANT)),)
+    # turn on Proguard by default for user & userdebug build
+    LOCAL_PROGUARD_ENABLED :=full
+endif
+endif
+ifeq ($(LOCAL_PROGUARD_ENABLED),disabled)
+    # the package explicitly request to disable proguard.
+    LOCAL_PROGUARD_ENABLED :=
+endif
+proguard_options_file :=
+ifneq ($(LOCAL_PROGUARD_ENABLED),custom)
+ifneq ($(all_resources),)
+    proguard_options_file := $(package_expected_intermediates_COMMON)/proguard_options
+endif # all_resources
+endif # !custom
+LOCAL_PROGUARD_FLAGS := $(addprefix -include ,$(proguard_options_file)) $(LOCAL_PROGUARD_FLAGS)
+
+ifeq (true,$(WITH_DEXPREOPT))
+ifneq (,$(LOCAL_SRC_FILES))
+ifndef LOCAL_DEX_PREOPT
+LOCAL_DEX_PREOPT := true
+endif
+endif
+endif
+
+# The dex files go in the package, so we don't
+# want to install them separately for this module.
+old_DONT_INSTALL_DEX_FILES := $(DONT_INSTALL_DEX_FILES)
+DONT_INSTALL_DEX_FILES := true
+#################################
+include $(BUILD_SYSTEM)/java.mk
+#################################
+DONT_INSTALL_DEX_FILES := $(old_DONT_INSTALL_DEX_FILES)
+old_DONT_INSTALL_DEX_FILES =
+
+full_android_manifest := $(LOCAL_PATH)/$(LOCAL_MANIFEST_FILE)
+$(LOCAL_INTERMEDIATE_TARGETS): \
+       PRIVATE_ANDROID_MANIFEST := $(full_android_manifest)
+
+ifneq ($(all_resources),)
+
+# Since we don't know where the real R.java file is going to end up,
+# we need to use another file to stand in its place.  We'll just
+# copy the generated file to src/R.stamp, which means it will
+# have the same contents and timestamp as the actual file.
+#
+# At the same time, this will copy the R.java file to a central
+# 'R' directory to make it easier to add the files to an IDE.
+#
+#TODO: use PRIVATE_SOURCE_INTERMEDIATES_DIR instead of
+#      $(intermediates.COMMON)/src
+ifneq ($(package_expected_intermediates_COMMON),$(intermediates.COMMON))
+  $(error $(LOCAL_MODULE): internal error: expected intermediates.COMMON "$(package_expected_intermediates_COMMON)" != intermediates.COMMON "$(intermediates.COMMON)")
+endif
+
+$(R_file_stamp): PRIVATE_RESOURCE_PUBLICS_OUTPUT := \
+                       $(intermediates.COMMON)/public_resources.xml
+$(R_file_stamp): PRIVATE_PROGUARD_OPTIONS_FILE := $(proguard_options_file)
+$(R_file_stamp): $(all_res_assets) $(full_android_manifest) $(AAPT) | $(ACP)
+       @echo "target R.java/Manifest.java: $(PRIVATE_MODULE) ($@)"
+       @rm -f $@
+       $(create-resource-java-files)
+       $(hide) for GENERATED_MANIFEST_FILE in `find $(PRIVATE_SOURCE_INTERMEDIATES_DIR) \
+                                       -name Manifest.java 2> /dev/null`; do \
+               dir=`grep package $$GENERATED_MANIFEST_FILE | head -n1 | \
+                       awk '{print $$2}' | tr -d ";" | tr . /`; \
+               mkdir -p $(TARGET_COMMON_OUT_ROOT)/R/$$dir; \
+               $(ACP) -fpt $$GENERATED_MANIFEST_FILE $(TARGET_COMMON_OUT_ROOT)/R/$$dir; \
+       done;
+       $(hide) for GENERATED_R_FILE in `find $(PRIVATE_SOURCE_INTERMEDIATES_DIR) \
+                                       -name R.java 2> /dev/null`; do \
+               dir=`grep package $$GENERATED_R_FILE | head -n1 | \
+                       awk '{print $$2}' | tr -d ";" | tr . /`; \
+               mkdir -p $(TARGET_COMMON_OUT_ROOT)/R/$$dir; \
+               $(ACP) -fpt $$GENERATED_R_FILE $(TARGET_COMMON_OUT_ROOT)/R/$$dir \
+                       || exit 31; \
+               $(ACP) -fpt $$GENERATED_R_FILE $@ || exit 32; \
+       done; \
+
+$(proguard_options_file): $(R_file_stamp)
+
+ifdef LOCAL_EXPORT_PACKAGE_RESOURCES
+# Put this module's resources into a PRODUCT-agnositc package that
+# other packages can use to build their own PRODUCT-agnostic R.java (etc.)
+# files.
+resource_export_package := $(intermediates.COMMON)/package-export.apk
+$(R_file_stamp): $(resource_export_package)
+
+# add-assets-to-package looks at PRODUCT_AAPT_CONFIG, but this target
+# can't know anything about PRODUCT.  Clear it out just for this target.
+$(resource_export_package): PRODUCT_AAPT_CONFIG :=
+$(resource_export_package): $(all_res_assets) $(full_android_manifest) $(AAPT)
+       @echo "target Export Resources: $(PRIVATE_MODULE) ($@)"
+       $(create-empty-package)
+       $(add-assets-to-package)
+endif
+
+# Other modules should depend on the BUILT module if
+# they want to use this module's R.java file.
+$(LOCAL_BUILT_MODULE): $(R_file_stamp)
+
+ifneq ($(full_classes_jar),)
+# If full_classes_jar is non-empty, we're building sources.
+# If we're building sources, the initial javac step (which
+# produces full_classes_compiled_jar) needs to ensure the
+# R.java and Manifest.java files have been generated first.
+$(full_classes_compiled_jar): $(R_file_stamp)
+endif
+
+endif  # all_resources
+
+ifeq ($(LOCAL_NO_STANDARD_LIBRARIES),true)
+# We need to explicitly clear this var so that we don't
+# inherit the value from whomever caused us to be built.
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_AAPT_INCLUDES :=
+else
+# Most packages should link against the resources defined by framework-res.
+# Even if they don't have their own resources, they may use framework
+# resources.
+ifneq ($(filter-out current,$(LOCAL_SDK_VERSION)),)
+# for released sdk versions, the platform resources were built into android.jar.
+framework_res_package_export := \
+       $(HISTORICAL_SDK_VERSIONS_ROOT)/$(LOCAL_SDK_VERSION)/android.jar
+framework_res_package_export_deps := $(framework_res_package_export)
+else # LOCAL_SDK_VERSION
+framework_res_package_export := \
+       $(call intermediates-dir-for,APPS,framework-res,,COMMON)/package-export.apk
+# We can't depend directly on the export.apk file; it won't get its
+# PRIVATE_ vars set up correctly if we do.  Instead, depend on the
+# corresponding R.stamp file, which lists the export.apk as a dependency.
+framework_res_package_export_deps := \
+       $(dir $(framework_res_package_export))src/R.stamp
+endif # LOCAL_SDK_VERSION
+$(R_file_stamp): $(framework_res_package_export_deps)
+$(LOCAL_INTERMEDIATE_TARGETS): \
+       PRIVATE_AAPT_INCLUDES := $(framework_res_package_export)
+endif # LOCAL_NO_STANDARD_LIBRARIES
+
+ifneq ($(full_classes_jar),)
+$(LOCAL_BUILT_MODULE): PRIVATE_DEX_FILE := $(built_dex)
+$(LOCAL_BUILT_MODULE): $(built_dex)
+endif # full_classes_jar
+
+
+# Get the list of jni libraries to be included in the apk file.
+
+so_suffix := $($(my_prefix)SHLIB_SUFFIX)
+
+jni_shared_libraries := \
+    $(addprefix $($(my_prefix)OUT_INTERMEDIATE_LIBRARIES)/, \
+      $(addsuffix $(so_suffix), \
+        $(LOCAL_JNI_SHARED_LIBRARIES)))
+
+# Pick a key to sign the package with.  If this package hasn't specified
+# an explicit certificate, use the default.
+# Secure release builds will have their packages signed after the fact,
+# so it's ok for these private keys to be in the clear.
+ifeq ($(LOCAL_CERTIFICATE),)
+    LOCAL_CERTIFICATE := testkey
+endif
+
+ifeq ($(LOCAL_CERTIFICATE),EXTERNAL)
+  # The special value "EXTERNAL" means that we will sign it with the
+  # default testkey, apply predexopt, but then expect the final .apk
+  # (after dexopting) to be signed by an outside tool.
+  LOCAL_CERTIFICATE := testkey
+  PACKAGES.$(LOCAL_PACKAGE_NAME).EXTERNAL_KEY := 1
+endif
+
+# If this is not an absolute certificate, assign it to a generic one.
+ifeq ($(dir $(strip $(LOCAL_CERTIFICATE))),./)
+    LOCAL_CERTIFICATE := $(SRC_TARGET_DIR)/product/security/$(LOCAL_CERTIFICATE)
+endif
+private_key := $(LOCAL_CERTIFICATE).pk8
+certificate := $(LOCAL_CERTIFICATE).x509.pem
+
+$(LOCAL_BUILT_MODULE): $(private_key) $(certificate) $(SIGNAPK_JAR)
+$(LOCAL_BUILT_MODULE): PRIVATE_PRIVATE_KEY := $(private_key)
+$(LOCAL_BUILT_MODULE): PRIVATE_CERTIFICATE := $(certificate)
+
+PACKAGES.$(LOCAL_PACKAGE_NAME).PRIVATE_KEY := $(private_key)
+PACKAGES.$(LOCAL_PACKAGE_NAME).CERTIFICATE := $(certificate)
+
+# Define the rule to build the actual package.
+$(LOCAL_BUILT_MODULE): $(AAPT) | $(ZIPALIGN)
+ifeq ($(LOCAL_DEX_PREOPT),true)
+# Make sure the boot jars get dexpreopt-ed first
+$(LOCAL_BUILT_MODULE): $(DEXPREOPT_BOOT_ODEXS) | $(DEXPREOPT) $(DEXOPT)
+endif
+$(LOCAL_BUILT_MODULE): PRIVATE_JNI_SHARED_LIBRARIES := $(jni_shared_libraries)
+ifneq ($(TARGET_BUILD_APPS),)
+    # Include all resources for unbundled apps.
+    $(LOCAL_BUILT_MODULE): PRODUCT_AAPT_CONFIG :=
+endif
+$(LOCAL_BUILT_MODULE): $(all_res_assets) $(jni_shared_libraries) $(full_android_manifest)
+       @echo "target Package: $(PRIVATE_MODULE) ($@)"
+       $(create-empty-package)
+       $(add-assets-to-package)
+ifneq ($(jni_shared_libraries),)
+       $(add-jni-shared-libs-to-package)
+endif
+ifneq ($(full_classes_jar),)
+       $(add-dex-to-package)
+endif
+       $(sign-package)
+       @# Alignment must happen after all other zip operations.
+       $(align-package)
+ifeq ($(LOCAL_DEX_PREOPT),true)
+       $(hide) rm -f $(patsubst %.apk,%.odex,$@)
+       $(call dexpreopt-one-file,$@,$(patsubst %.apk,%.odex,$@))
+       $(call dexpreopt-remove-classes.dex,$@)
+
+built_odex := $(basename $(LOCAL_BUILT_MODULE)).odex
+$(built_odex): $(LOCAL_BUILT_MODULE)
+endif
+
+# Save information about this package
+PACKAGES.$(LOCAL_PACKAGE_NAME).OVERRIDES := $(strip $(LOCAL_OVERRIDES_PACKAGES))
+PACKAGES.$(LOCAL_PACKAGE_NAME).RESOURCE_FILES := $(all_resources)
+
+PACKAGES := $(PACKAGES) $(LOCAL_PACKAGE_NAME)
+
+endif # skip_definition
diff --git a/build/core/pathmap.mk b/build/core/pathmap.mk
new file mode 100644 (file)
index 0000000..fe7ba1a
--- /dev/null
@@ -0,0 +1,102 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# A central place to define mappings to paths, to avoid hard-coding
+# them in Android.mk files.
+#
+# TODO: Allow each project to define stuff like this before the per-module
+#       Android.mk files are included, so we don't need to have a big central
+#       list.
+#
+
+#
+# A mapping from shorthand names to include directories.
+#
+pathmap_INCL := \
+    bluedroid:system/bluetooth/bluedroid/include \
+    bluez:external/bluetooth/bluez \
+    glib:external/bluetooth/glib \
+    bootloader:bootable/bootloader/legacy/include \
+    corecg:external/skia/include/core \
+    dbus:external/dbus \
+    frameworks-base:frameworks/base/include \
+    graphics:external/skia/include/core \
+    libc:bionic/libc/include \
+    libdrm1:frameworks/base/media/libdrm/mobile1/include \
+    libhardware:hardware/libhardware/include \
+    libhardware_legacy:hardware/libhardware_legacy/include \
+    libhost:build/libs/host/include \
+    libm:bionic/libm/include \
+    libnativehelper:dalvik/libnativehelper/include \
+    libpagemap:system/extras/libpagemap/include \
+    libril:hardware/ril/include \
+    libstdc++:bionic/libstdc++/include \
+    libthread_db:bionic/libthread_db/include \
+    mkbootimg:system/core/mkbootimg \
+    recovery:bootable/recovery \
+    system-core:system/core/include
+
+#
+# Returns the path to the requested module's include directory,
+# relative to the root of the source tree.  Does not handle external
+# modules.
+#
+# $(1): a list of modules (or other named entities) to find the includes for
+#
+define include-path-for
+$(foreach n,$(1),$(patsubst $(n):%,%,$(filter $(n):%,$(pathmap_INCL))))
+endef
+
+#
+# Many modules expect to be able to say "#include <jni.h>",
+# so make it easy for them to find the correct path.
+#
+JNI_H_INCLUDE := $(call include-path-for,libnativehelper)/nativehelper
+
+#
+# A list of all source roots under frameworks/base, which will be
+# built into the android.jar.
+#
+# Note - "common" is included here, even though it is also built
+# into a static library (android-common) for unbundled use.  This
+# is so common and the other framework libraries can have mutual
+# interdependencies.
+#
+FRAMEWORKS_BASE_SUBDIRS := \
+       $(addsuffix /java, \
+           core \
+           graphics \
+           location \
+           media \
+           drm \
+           opengl \
+           sax \
+           telephony \
+           wifi \
+           vpn \
+           keystore \
+           voip \
+        )
+
+#
+# A version of FRAMEWORKS_BASE_SUBDIRS that is expanded to full paths from
+# the root of the tree.  This currently needs to be here so that other libraries
+# and apps can find the .aidl files in the framework, though we should really
+# figure out a better way to do this.
+#
+FRAMEWORKS_BASE_JAVA_SRC_DIRS := \
+       $(addprefix frameworks/base/,$(FRAMEWORKS_BASE_SUBDIRS))
diff --git a/build/core/prebuilt.mk b/build/core/prebuilt.mk
new file mode 100644 (file)
index 0000000..b4717e0
--- /dev/null
@@ -0,0 +1,95 @@
+###########################################################
+## Standard rules for copying files that are prebuilt
+##
+## Additional inputs from base_rules.make:
+## None.
+##
+###########################################################
+
+ifneq ($(LOCAL_PREBUILT_LIBS),)
+$(error dont use LOCAL_PREBUILT_LIBS anymore LOCAL_PATH=$(LOCAL_PATH))
+endif
+ifneq ($(LOCAL_PREBUILT_EXECUTABLES),)
+$(error dont use LOCAL_PREBUILT_EXECUTABLES anymore LOCAL_PATH=$(LOCAL_PATH))
+endif
+ifneq ($(LOCAL_PREBUILT_JAVA_LIBRARIES),)
+$(error dont use LOCAL_PREBUILT_JAVA_LIBRARIES anymore LOCAL_PATH=$(LOCAL_PATH))
+endif
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+# Deal with the OSX library timestamp issue when installing
+# a prebuilt simulator library.
+ifneq ($(filter STATIC_LIBRARIES SHARED_LIBRARIES,$(LOCAL_MODULE_CLASS)),)
+  prebuilt_module_is_a_library := true
+else
+  prebuilt_module_is_a_library :=
+endif
+
+PACKAGES.$(LOCAL_MODULE).OVERRIDES := $(strip $(LOCAL_OVERRIDES_PACKAGES))
+
+# Ensure that prebuilt .apks have been aligned.
+ifneq ($(filter APPS,$(LOCAL_MODULE_CLASS)),)
+$(LOCAL_BUILT_MODULE) : $(LOCAL_PATH)/$(LOCAL_SRC_FILES) | $(ZIPALIGN)
+       $(transform-prebuilt-to-target-with-zipalign)
+else
+ifneq ($(LOCAL_PREBUILT_STRIP_COMMENTS),)
+$(LOCAL_BUILT_MODULE) : $(LOCAL_PATH)/$(LOCAL_SRC_FILES)
+       $(transform-prebuilt-to-target-strip-comments)
+else
+$(LOCAL_BUILT_MODULE) : $(LOCAL_PATH)/$(LOCAL_SRC_FILES) | $(ACP)
+       $(transform-prebuilt-to-target)
+endif
+endif
+
+ifeq ($(LOCAL_IS_HOST_MODULE)$(LOCAL_MODULE_CLASS),JAVA_LIBRARIES)
+# for target java libraries, the LOCAL_BUILT_MODULE is in a product-specific dir,
+# while the deps should be in the common dir, so we make a copy in the common dir.
+common_library_jar := $(call intermediates-dir-for,JAVA_LIBRARIES,$(LOCAL_MODULE),,COMMON)/$(notdir $(LOCAL_BUILT_MODULE))
+$(common_library_jar) : $(LOCAL_PATH)/$(LOCAL_SRC_FILES) | $(ACP)
+       $(transform-prebuilt-to-target)
+endif
+
+ifeq ($(LOCAL_CERTIFICATE),EXTERNAL)
+  # The magic string "EXTERNAL" means this package will be signed with
+  # the test key throughout the build process, but we expect the final
+  # package to be signed with a different key.
+  #
+  # This can be used for packages where we don't have access to the
+  # keys, but want the package to be predexopt'ed.
+  LOCAL_CERTIFICATE := testkey
+  PACKAGES.$(LOCAL_MODULE).EXTERNAL_KEY := 1
+endif
+ifeq ($(LOCAL_CERTIFICATE),)
+  ifneq ($(filter APPS,$(LOCAL_MODULE_CLASS)),)
+    # It is now a build error to add a prebuilt .apk without
+    # specifying a key for it.
+    $(error No LOCAL_CERTIFICATE specified for prebuilt "$(LOCAL_SRC_FILES)")
+  endif
+else ifeq ($(LOCAL_CERTIFICATE),PRESIGNED)
+  # The magic string "PRESIGNED" means this package is already checked
+  # signed with its release key.
+  #
+  # By setting .CERTIFICATE but not .PRIVATE_KEY, this package will be
+  # mentioned in apkcerts.txt (with certificate set to "PRESIGNED")
+  # but the dexpreopt process will not try to re-sign the app.
+  PACKAGES.$(LOCAL_MODULE).CERTIFICATE := PRESIGNED
+  PACKAGES := $(PACKAGES) $(LOCAL_MODULE)
+else
+  # If this is not an absolute certificate, assign it to a generic one.
+  ifeq ($(dir $(strip $(LOCAL_CERTIFICATE))),./)
+      LOCAL_CERTIFICATE := $(SRC_TARGET_DIR)/product/security/$(LOCAL_CERTIFICATE)
+  endif
+
+  PACKAGES.$(LOCAL_MODULE).PRIVATE_KEY := $(LOCAL_CERTIFICATE).pk8
+  PACKAGES.$(LOCAL_MODULE).CERTIFICATE := $(LOCAL_CERTIFICATE).x509.pem
+  PACKAGES := $(PACKAGES) $(LOCAL_MODULE)
+endif
+
+ifneq ($(prebuilt_module_is_a_library),)
+  ifneq ($(LOCAL_IS_HOST_MODULE),)
+       $(transform-host-ranlib-copy-hack)
+  else
+       $(transform-ranlib-copy-hack)
+  endif
+endif
diff --git a/build/core/prelink-linux-arm.map b/build/core/prelink-linux-arm.map
new file mode 100644 (file)
index 0000000..7daaf98
--- /dev/null
@@ -0,0 +1,213 @@
+# 0xC0000000 - 0xFFFFFFFF Kernel
+# 0xB0100000 - 0xBFFFFFFF Thread 0 Stack
+# 0xB0000000 - 0xB00FFFFF Linker
+# 0xA0000000 - 0xBFFFFFFF Prelinked System Libraries
+# 0x90000000 - 0x9FFFFFFF Prelinked App Libraries
+# 0x80000000 - 0x8FFFFFFF Non-prelinked Libraries
+# 0x40000000 - 0x7FFFFFFF mmap'd stuff
+# 0x10000000 - 0x3FFFFFFF Thread Stacks
+# 0x00000000 - 0x0FFFFFFF .text / .data / heap
+
+# Note: The general rule is that libraries should be aligned on 1MB
+# boundaries. For ease of updating this file, you will find a comment
+# on each line, indicating the observed size of the library, which is
+# one of:
+#
+#     [<64K] observed to be less than 64K
+#     [~1M] rounded up, one megabyte (similarly for other sizes)
+#     [???] no size observed, assumed to be one megabyte
+#
+# note: look at the LOAD sections in the library header:
+#
+#   arm-eabi-objdump -x <lib>
+#
+
+# core system libraries
+libdl.so                0xAFF00000 # [<64K]
+libc.so                 0xAFD00000 # [~2M]
+libstdc++.so            0xAFC00000 # [<64K]
+libm.so                 0xAFB00000 # [~1M]
+liblog.so               0xAFA00000 # [<64K]
+libcutils.so            0xAF900000 # [~1M]
+libthread_db.so         0xAF800000 # [<64K]
+libz.so                 0xAF700000 # [~1M]
+libevent.so             0xAF600000 # [???]
+libssl.so               0xAF400000 # [~2M]
+libcrypto.so            0xAF000000 # [~4M]
+libsysutils.so          0xAEF00000 # [~1M]
+
+# bluetooth
+liba2dp.so              0xAEE00000 # [~1M]
+audio.so                0xAED00000 # [~1M]
+input.so                0xAEC00000 # [~1M]
+libbluetoothd.so        0xAEA00000 # [~2M]
+libbluedroid.so         0xAE900000 # [<64K]
+libbluetooth.so         0xAE800000 # [~1M]
+libdbus.so              0xAE700000 # [~1M]
+
+# extended system libraries
+libril.so               0xAE600000 # [~1M]
+libreference-ril.so     0xAE500000 # [~1M]
+libwpa_client.so        0xAE400000 # [<64K]
+libnetutils.so          0xAE300000 # [~1M]
+
+# core dalvik runtime support
+libandroid_servers.so   0xAE200000 # [~1M]
+libicuuc.so             0xADE00000 # [~4M]
+libicui18n.so           0xAD900000 # [~5M]
+libandroid_runtime.so   0xAD300000 # [~6M]
+libnativehelper.so      0xAD100000 # [~2M]
+libdvm-ARM.so           0xAD000000 # [???]
+libdvm.so               0xACA00000 # [~6M]
+# Note: libicudata.so intentionally omitted
+
+# graphics
+libpixelflinger.so      0xAC900000 # [~1M]
+# libcorecg is for backward-compatibility with donut
+libcorecg.so            0xAC800000 # [???]
+libsurfaceflinger_client.so 0xAC700000 # [~1M]
+libsurfaceflinger.so    0xAC500000 # [~2M]
+libGLES_android.so      0xAC400000 # [~1M]
+libagl.so               0xAC300000 # [???]
+
+libGLESv1_CM.so         0xAC200000 # [~1M]
+libGLESv2.so            0xAC100000 # [~1M]
+libOpenVG_CM.so         0xAC000000 # [???]
+libOpenVGU_CM.so        0xABF00000 # [???]
+libEGL.so               0xABE00000 # [~1M]
+libETC1.so              0xABD00000 # [<64K]
+
+libacc.so               0xABC00000 # [~1M]
+
+libexif.so              0xABB00000 # [~1M]
+libcamera_client.so     0xABA80000 # [~1M]
+libui.so                0xAB900000 # [~1M]
+libgui.so               0xAB800000 # [~1M]
+libskia.so              0xAB100000 # [~2M]
+librs_jni.so            0xAB000000 # [~1M]
+libRS.so                0xA9E00000 # [~2M]
+libandroid.so           0xA9D80000 # [<64K]
+libjnigraphics.so       0xA9D00000 # [<64K]
+libskiagl.so            0xA9C00000 # [~1M]
+
+# audio
+libFLAC.so              0xA9B00000 # [???]
+libaudiopolicy.so       0xA9A00000 # [~1M]
+libeffects.so           0xA9980000 # [<64K]
+libaudioeffect_jni.so   0xA9900000 # [<64K]
+libsoundpool.so         0xA9800000 # [~1M]
+libaudio.so             0xA9700000 # [~1M]
+libspeech.so            0xA9600000 # [~1M]
+libsonivox.so           0xA9500000 # [~1M]
+libvorbisidec.so        0xA9400000 # [~1M]
+libmedia_jni.so         0xA9300000 # [~1M]
+libmediaplayerservice.so 0xA9200000 # [~1M]
+libmedia.so             0xA9000000 # [~2M]
+libFFTEm.so             0xA8F00000 # [~1M]
+libSR_AudioIn.so        0xA8E00000 # [~1M] for external/srec
+libaudioflinger.so      0xA8D00000 # [~1M]
+
+# assorted system libraries
+libsqlite.so            0xA8B00000 # [~2M]
+libexpat.so             0xA8A00000 # [~1M]
+libwebcore.so           0xA8300000 # [~7M]
+libbinder.so            0xA8200000 # [~1M]
+libutils.so             0xA8100000 # [~1M]
+libcameraservice.so     0xA8000000 # [~1M]
+libhardware.so          0xA7F00000 # [<64K]
+libhardware_legacy.so   0xA7E00000 # [~1M]
+libapp_process.so       0xA7D00000 # [???]
+libsystem_server.so     0xA7C00000 # [~1M]
+libime.so               0xA7B00000 # [???]
+libgps.so               0xA7A00000 # [~1M]
+libcamera.so            0xA7900000 # [~1M]
+liboemcamera.so         0xA7700000 # [~2M]
+libdiskconfig.so        0xA7600000 # [<64K]
+libemoji.so             0xA7500000 # [<64K]
+libjni_latinime.so      0xA7400000 # [~1M]
+libjni_pinyinime.so     0xA7300000 # [~1M]
+libttssynthproxy.so     0xA7200000 # [~1M] for frameworks/base
+libttspico.so           0xA7000000 # [~2M] for external/svox
+
+# pv libraries
+libpvasf.so                    0xA6F00000 # [???]
+libpvasfreg.so                 0xA6E00000 # [???]
+libomx_sharedlibrary.so        0xA6D00000 # [~1M]
+libopencore_download.so        0xA6C00000 # [~1M]
+libopencore_downloadreg.so     0xA6B00000 # [~1M]
+libopencore_net_support.so     0xA6800000 # [~3M]
+libopencore_rtsp.so            0xA6200000 # [~6M]
+libopencore_rtspreg.so         0xA6100000 # [~1M]
+libopencore_author.so          0xA5D00000 # [~4M]
+libomx_aacdec_sharedlibrary.so 0xA5B00000 # [~2M]
+libomx_amrdec_sharedlibrary.so 0xA5A00000 # [~1M]
+libomx_amrenc_sharedlibrary.so 0xA5900000 # [~1M]
+libomx_avcdec_sharedlibrary.so 0xA5800000 # [~1M]
+libomx_avcenc_sharedlibrary.so 0xA5700000 # [???]
+libomx_m4vdec_sharedlibrary.so 0xA5600000 # [~1M]
+libomx_m4venc_sharedlibrary.so 0xA5500000 # [???]
+libomx_mp3dec_sharedlibrary.so 0xA5400000 # [~1M]
+libopencore_mp4local.so        0xA5200000 # [~2M]
+libopencore_mp4localreg.so     0xA5100000 # [~1M]
+libopencore_player.so          0xA4800000 # [~9M]
+
+# opencore hardware support
+libmm-adspsvc.so              0xA4700000 # [<64K]
+libOmxCore.so                 0xA4600000 # [<64K]
+libOmxMpeg4Dec.so             0xA4500000 # [~1M]
+libOmxH264Dec.so              0xA4400000 # [~1M]
+libOmxVidEnc.so               0xA4300000 # [~1M]
+libopencorehw.so              0xA4200000 # [~1M]
+libOmxVdec.so                 0xA4100000 # [~1M]
+libmm-omxcore.so              0xA4000000 # [<64K]
+
+# pv libraries
+libopencore_common.so         0xA3900000 # [~7M]
+libqcomm_omx.so               0xA3800000 # [<64K]
+
+# stagefright libraries
+libstagefright_amrnb_common.so     0xA3700000 # [~1M]
+libstagefright_avc_common.so       0xA3600000 # [~1M]
+libstagefright_color_conversion.so 0xA3500000 # [<64K]
+libstagefright_omx.so              0xA3400000 # [~1M]
+libstagefrighthw.so                0xA3300000 # [~1M]
+libstagefright.so                  0xA2F00000 # [~4M]
+
+# libraries for specific hardware
+libgsl.so               0xA2E00000 # [~1M]
+libhtc_acoustic.so      0xA2D00000 # [<64K]
+libhtc_ril.so           0xA2C00000 # [~1M]
+liblvmxipc.so           0xA2B00000 # [~1M] for vendor/nxp
+libreference-cdma-sms.so 0xA2A00000 # [<64K] for hardware/ril
+
+# libraries for specific apps or temporary libraries
+libcam_ipl.so           0x9F000000 # [???]
+libwbxml.so             0x9EF00000 # [???]
+libwbxml_jni.so         0x9EE00000 # [~1M]
+libxml2wbxml.so         0x9EB00000 # [~1M]
+libdrm1.so              0x9EA00000 # [~1M]
+libdrm1_jni.so          0x9E900000 # [<64K]
+libwapcore.so           0x9E800000 # [???]
+libstreetview.so        0x9E700000 # [???]
+libwapbrowsertest.so    0x9E600000 # [???]
+libminiglobe.so         0x9E500000 # [???]
+libearth.so             0x9E400000 # [???]
+libembunit.so           0x9E300000 # [<64K]
+libneon.so              0x9E200000 # [???]
+libjni_example.so       0x9E100000 # [???]
+libjni_load_test.so     0x9E000000 # [???]
+libjni_lib_test.so      0x9DF00000 # [???]
+librunperf.so           0x9DE00000 # [???]
+libctest.so             0x9DD00000 # [<64K]
+libUAPI_jni.so          0x9DC00000 # [???]
+librpc.so               0x9DB00000 # [~1M]
+libtrace_test.so        0x9DA00000 # [???]
+libsrec_jni.so          0x9D800000 # [~2M]
+libjpeg.so              0x9D700000 # [~1M]
+libiprouteutil.so       0x9D600000 # [~1M] for external/iproute2
+libnetlink.so           0x9D500000 # [<64K] for external/iproute2
+libpagemap.so           0x9D400000 # [<64K] for system/extras/libpagemap
+libstlport.so           0x9D100000 # [~3M] for external/stlport
+libzxing.so             0x9D000000 # [<64K] for goggles
+libinterstitial.so      0x9CF00000 # [<64K] for goggles
+liblept.so              0x9CA00000 # [~5M] for external/leptonica
diff --git a/build/core/process_wrapper.sh b/build/core/process_wrapper.sh
new file mode 100644 (file)
index 0000000..9c3104e
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# When using a process wrapper, this is the top-level
+# command that is executed instead of the server
+# command.  It starts a new xterm in which the user can
+# interact with the new process.
+#
+# Inside of the xterm is a gdb session, through which
+# the user can debug the new process.
+
+# Save away these variables, since we may loose them
+# when starting in the xterm.
+export PREV_LD_LIBRARY_PATH=$LD_LIBRARY_PATH
+export PREV_PATH=$PATH
+
+gnome-terminal -t "Wrapper: $1" --disable-factory -x $2/process_wrapper_gdb.sh "$@"
+
diff --git a/build/core/process_wrapper_gdb.cmds b/build/core/process_wrapper_gdb.cmds
new file mode 100644 (file)
index 0000000..f5bdd21
--- /dev/null
@@ -0,0 +1 @@
+run
diff --git a/build/core/process_wrapper_gdb.sh b/build/core/process_wrapper_gdb.sh
new file mode 100644 (file)
index 0000000..38b948a
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# This is the command running inside the xterm of our
+# debug wrapper.  It needs to take care of starting
+# the server command, so it can attach to the parent
+# process.  In addition, here we run the command inside
+# of a gdb session to allow for debugging.
+
+# On some systems, running xterm will cause LD_LIBRARY_PATH
+# to be cleared, so restore it and PATH to be safe.
+export PATH=$PREV_PATH
+export LD_LIBRARY_PATH=$PREV_LD_LIBRARY_PATH
+
+# Start binderproc (or whatever sub-command is being run)
+# inside of gdb, giving gdb an initial command script to
+# automatically run the process without user intervention.
+gdb -q -x $2/process_wrapper_gdb.cmds --args "$@"
diff --git a/build/core/product.mk b/build/core/product.mk
new file mode 100644 (file)
index 0000000..4a0ee01
--- /dev/null
@@ -0,0 +1,189 @@
+#
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Functions for including AndroidProducts.mk files
+#
+
+#
+# Returns the list of all AndroidProducts.mk files.
+# $(call ) isn't necessary.
+#
+define _find-android-products-files
+$(shell test -d device && find device -maxdepth 6 -name AndroidProducts.mk) \
+  $(shell test -d vendor && find vendor -maxdepth 6 -name AndroidProducts.mk) \
+  $(SRC_TARGET_DIR)/product/AndroidProducts.mk
+endef
+
+#
+# Returns the sorted concatenation of PRODUCT_MAKEFILES
+# variables set in the given AndroidProducts.mk files.
+# $(1): the list of AndroidProducts.mk files.
+#
+define get-product-makefiles
+$(sort \
+  $(foreach f,$(1), \
+    $(eval PRODUCT_MAKEFILES :=) \
+    $(eval LOCAL_DIR := $(patsubst %/,%,$(dir $(f)))) \
+    $(eval include $(f)) \
+    $(PRODUCT_MAKEFILES) \
+   ) \
+  $(eval PRODUCT_MAKEFILES :=) \
+  $(eval LOCAL_DIR :=) \
+ )
+endef
+
+#
+# Returns the sorted concatenation of all PRODUCT_MAKEFILES
+# variables set in all AndroidProducts.mk files.
+# $(call ) isn't necessary.
+#
+define get-all-product-makefiles
+$(call get-product-makefiles,$(_find-android-products-files))
+endef
+
+#
+# Functions for including product makefiles
+#
+
+_product_var_list := \
+    PRODUCT_NAME \
+    PRODUCT_MODEL \
+    PRODUCT_LOCALES \
+    PRODUCT_PACKAGES \
+    PRODUCT_DEVICE \
+    PRODUCT_MANUFACTURER \
+    PRODUCT_BRAND \
+    PRODUCT_PROPERTY_OVERRIDES \
+    PRODUCT_CHARACTERISTICS \
+    PRODUCT_COPY_FILES \
+    PRODUCT_OTA_PUBLIC_KEYS \
+    PRODUCT_PACKAGE_OVERLAYS \
+    DEVICE_PACKAGE_OVERLAYS \
+    PRODUCT_CONTRIBUTORS_FILE \
+    PRODUCT_TAGS \
+    PRODUCT_SDK_ADDON_NAME \
+    PRODUCT_SDK_ADDON_COPY_FILES \
+    PRODUCT_SDK_ADDON_COPY_MODULES \
+    PRODUCT_SDK_ADDON_DOC_MODULE \
+    PRODUCT_DEFAULT_WIFI_CHANNELS
+
+define dump-product
+$(info ==== $(1) ====)\
+$(foreach v,$(_product_var_list),\
+$(info PRODUCTS.$(1).$(v) := $(PRODUCTS.$(1).$(v))))\
+$(info --------)
+endef
+
+define dump-products
+$(foreach p,$(PRODUCTS),$(call dump-product,$(p)))
+endef
+
+#
+# $(1): product to inherit
+#
+# Does three things:
+#  1. Inherits all of the variables from $1.
+#  2. Records the inheritance in the .INHERITS_FROM variable
+#  3. Records that we've visited this node, in ALL_PRODUCTS
+#
+define inherit-product
+  $(foreach v,$(_product_var_list), \
+      $(eval $(v) := $($(v)) $(INHERIT_TAG)$(strip $(1)))) \
+  $(eval inherit_var := \
+      PRODUCTS.$(strip $(word 1,$(_include_stack))).INHERITS_FROM) \
+  $(eval $(inherit_var) := $(sort $($(inherit_var)) $(strip $(1)))) \
+  $(eval inherit_var:=) \
+  $(eval ALL_PRODUCTS := $(sort $(ALL_PRODUCTS) $(word 1,$(_include_stack))))
+endef
+
+
+#
+# Do inherit-product only if $(1) exists
+#
+define inherit-product-if-exists
+  $(if $(wildcard $(1)),$(call inherit-product,$(1)),)
+endef
+
+#
+# $(1): product makefile list
+#
+#TODO: check to make sure that products have all the necessary vars defined
+define import-products
+$(call import-nodes,PRODUCTS,$(1),$(_product_var_list))
+endef
+
+
+#
+# Does various consistency checks on all of the known products.
+# Takes no parameters, so $(call ) is not necessary.
+#
+define check-all-products
+$(if ,, \
+  $(eval _cap_names :=) \
+  $(foreach p,$(PRODUCTS), \
+    $(eval pn := $(strip $(PRODUCTS.$(p).PRODUCT_NAME))) \
+    $(if $(pn),,$(error $(p): PRODUCT_NAME must be defined.)) \
+    $(if $(filter $(pn),$(_cap_names)), \
+      $(error $(p): PRODUCT_NAME must be unique; "$(pn)" already used by $(strip \
+          $(foreach \
+            pp,$(PRODUCTS),
+              $(if $(filter $(pn),$(PRODUCTS.$(pp).PRODUCT_NAME)), \
+                $(pp) \
+               ))) \
+       ) \
+     ) \
+    $(eval _cap_names += $(pn)) \
+    $(if $(call is-c-identifier,$(pn)),, \
+      $(error $(p): PRODUCT_NAME must be a valid C identifier, not "$(pn)") \
+     ) \
+    $(eval pb := $(strip $(PRODUCTS.$(p).PRODUCT_BRAND))) \
+    $(if $(pb),,$(error $(p): PRODUCT_BRAND must be defined.)) \
+    $(foreach cf,$(strip $(PRODUCTS.$(p).PRODUCT_COPY_FILES)), \
+      $(if $(filter 2,$(words $(subst :,$(space),$(cf)))),, \
+        $(error $(p): malformed COPY_FILE "$(cf)") \
+       ) \
+     ) \
+   ) \
+)
+endef
+
+
+#
+# Returns the product makefile path for the product with the provided name
+#
+# $(1): short product name like "generic"
+#
+define _resolve-short-product-name
+  $(eval pn := $(strip $(1)))
+  $(eval p := \
+      $(foreach p,$(PRODUCTS), \
+          $(if $(filter $(pn),$(PRODUCTS.$(p).PRODUCT_NAME)), \
+            $(p) \
+       )) \
+   )
+  $(eval p := $(sort $(p)))
+  $(if $(filter 1,$(words $(p))), \
+    $(p), \
+    $(if $(filter 0,$(words $(p))), \
+      $(error No matches for product "$(pn)"), \
+      $(error Product "$(pn)" ambiguous: matches $(p)) \
+    ) \
+  )
+endef
+define resolve-short-product-name
+$(strip $(call _resolve-short-product-name,$(1)))
+endef
diff --git a/build/core/product_config.mk b/build/core/product_config.mk
new file mode 100644 (file)
index 0000000..70ac894
--- /dev/null
@@ -0,0 +1,311 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# ---------------------------------------------------------------
+# Generic functions
+# TODO: Move these to definitions.make once we're able to include
+# definitions.make before config.make.
+
+###########################################################
+## Return non-empty if $(1) is a C identifier; i.e., if it
+## matches /^[a-zA-Z_][a-zA-Z0-9_]*$/.  We do this by first
+## making sure that it isn't empty and doesn't start with
+## a digit, then by removing each valid character.  If the
+## final result is empty, then it was a valid C identifier.
+##
+## $(1): word to check
+###########################################################
+
+_ici_digits := 0 1 2 3 4 5 6 7 8 9
+_ici_alphaunderscore := \
+    a b c d e f g h i j k l m n o p q r s t u v w x y z \
+    A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _
+define is-c-identifier
+$(strip \
+  $(if $(1), \
+    $(if $(filter $(addsuffix %,$(_ici_digits)),$(1)), \
+     , \
+      $(eval w := $(1)) \
+      $(foreach c,$(_ici_digits) $(_ici_alphaunderscore), \
+        $(eval w := $(subst $(c),,$(w))) \
+       ) \
+      $(if $(w),,TRUE) \
+      $(eval w :=) \
+     ) \
+   ) \
+ )
+endef
+
+# TODO: push this into the combo files; unfortunately, we don't even
+# know HOST_OS at this point.
+trysed := $(shell echo a | sed -E -e 's/a/b/' 2>/dev/null)
+ifeq ($(trysed),b)
+  SED_EXTENDED := sed -E
+else
+  trysed := $(shell echo c | sed -r -e 's/c/d/' 2>/dev/null)
+  ifeq ($(trysed),d)
+    SED_EXTENDED := sed -r
+  else
+    $(error Unknown sed version)
+  endif
+endif
+
+###########################################################
+## List all of the files in a subdirectory in a format
+## suitable for PRODUCT_COPY_FILES and
+## PRODUCT_SDK_ADDON_COPY_FILES
+##
+## $(1): Glob to match file name
+## $(2): Source directory
+## $(3): Target base directory
+###########################################################
+
+define find-copy-subdir-files
+$(shell find $(2) -name "$(1)" | $(SED_EXTENDED) "s:($(2)/?(.*)):\\1\\:$(3)/\\2:" | sed "s://:/:g")
+endef
+
+# ---------------------------------------------------------------
+
+# These are the valid values of TARGET_BUILD_VARIANT.  Also, if anything else is passed
+# as the variant in the PRODUCT-$TARGET_BUILD_PRODUCT-$TARGET_BUILD_VARIANT form,
+# it will be treated as a goal, and the eng variant will be used.
+INTERNAL_VALID_VARIANTS := user userdebug eng tests
+
+# ---------------------------------------------------------------
+# Provide "PRODUCT-<prodname>-<goal>" targets, which lets you build
+# a particular configuration without needing to set up the environment.
+#
+product_goals := $(strip $(filter PRODUCT-%,$(MAKECMDGOALS)))
+ifdef product_goals
+  # Scrape the product and build names out of the goal,
+  # which should be of the form PRODUCT-<productname>-<buildname>.
+  #
+  ifneq ($(words $(product_goals)),1)
+    $(error Only one PRODUCT-* goal may be specified; saw "$(product_goals)")
+  endif
+  goal_name := $(product_goals)
+  product_goals := $(patsubst PRODUCT-%,%,$(product_goals))
+  product_goals := $(subst -, ,$(product_goals))
+  ifneq ($(words $(product_goals)),2)
+    $(error Bad PRODUCT-* goal "$(goal_name)")
+  endif
+
+  # The product they want
+  TARGET_PRODUCT := $(word 1,$(product_goals))
+
+  # The variant they want
+  TARGET_BUILD_VARIANT := $(word 2,$(product_goals))
+
+  # The build server wants to do make PRODUCT-dream-installclean
+  # which really means TARGET_PRODUCT=dream make installclean.
+  ifneq ($(filter-out $(INTERNAL_VALID_VARIANTS),$(TARGET_BUILD_VARIANT)),)
+       MAKECMDGOALS := $(MAKECMDGOALS) $(TARGET_BUILD_VARIANT)
+       TARGET_BUILD_VARIANT := eng
+    default_goal_substitution :=
+  else
+    default_goal_substitution := $(DEFAULT_GOAL)
+  endif
+
+  # For tests build, only build tests-build-target
+  ifeq (tests,$(TARGET_BUILD_VARIANT))
+    default_goal_substitution := tests-build-target
+  endif
+
+  # Hack to make the linux build servers use dexpreopt (emulator-based
+  # preoptimization). Most engineers don't use this type of target
+  # ("make PRODUCT-blah-user"), so this should only tend to happen when
+  # using buildbot.
+  # TODO: Remove this once host Dalvik preoptimization is working.
+  ifeq ($(TARGET_BUILD_VARIANT),user)
+    WITH_DEXPREOPT_buildbot := true
+  endif
+
+  # Replace the PRODUCT-* goal with the build goal that it refers to.
+  # Note that this will ensure that it appears in the same relative
+  # position, in case it matters.
+  #
+  # Note that modifying this will not affect the goals that make will
+  # attempt to build, but it's important because we inspect this value
+  # in certain situations (like for "make sdk").
+  #
+  MAKECMDGOALS := $(patsubst $(goal_name),$(default_goal_substitution),$(MAKECMDGOALS))
+
+  # Define a rule for the PRODUCT-* goal, and make it depend on the
+  # patched-up command-line goals as well as any other goals that we
+  # want to force.
+  #
+.PHONY: $(goal_name)
+$(goal_name): $(MAKECMDGOALS)
+endif
+# else: Use the value set in the environment or buildspec.mk.
+
+# ---------------------------------------------------------------
+# Provide "APP-<appname>" targets, which lets you build
+# an unbundled app.
+#
+unbundled_goals := $(strip $(filter APP-%,$(MAKECMDGOALS)))
+ifdef unbundled_goals
+  ifneq ($(words $(unbundled_goals)),1)
+    $(error Only one APP-* goal may be specified; saw "$(unbundled_goals)"))
+  endif
+  TARGET_BUILD_APPS := $(strip $(subst -, ,$(patsubst APP-%,%,$(unbundled_goals))))
+  ifneq ($(filter $(DEFAULT_GOAL),$(MAKECMDGOALS)),)
+    MAKECMDGOALS := $(patsubst $(unbundled_goals),,$(MAKECMDGOALS))
+  else
+    MAKECMDGOALS := $(patsubst $(unbundled_goals),$(DEFAULT_GOAL),$(MAKECMDGOALS))
+  endif
+
+.PHONY: $(unbundled_goals)
+$(unbundled_goals): $(MAKECMDGOALS)
+endif # unbundled_goals
+
+# ---------------------------------------------------------------
+# Include the product definitions.
+# We need to do this to translate TARGET_PRODUCT into its
+# underlying TARGET_DEVICE before we start defining any rules.
+#
+include $(BUILD_SYSTEM)/node_fns.mk
+include $(BUILD_SYSTEM)/product.mk
+include $(BUILD_SYSTEM)/device.mk
+
+ifneq ($(strip $(TARGET_BUILD_APPS)),)
+  # An unbundled app build needs only the core product makefiles.
+  $(call import-products,$(call get-product-makefiles,\
+      $(SRC_TARGET_DIR)/product/AndroidProducts.mk))
+else
+  # Read in all of the product definitions specified by the AndroidProducts.mk
+  # files in the tree.
+  #
+  #TODO: when we start allowing direct pointers to product files,
+  #    guarantee that they're in this list.
+  $(call import-products, $(get-all-product-makefiles))
+endif # TARGET_BUILD_APPS
+$(check-all-products)
+#$(dump-products)
+#$(error done)
+
+# Convert a short name like "sooner" into the path to the product
+# file defining that product.
+#
+INTERNAL_PRODUCT := $(call resolve-short-product-name, $(TARGET_PRODUCT))
+#$(error TARGET_PRODUCT $(TARGET_PRODUCT) --> $(INTERNAL_PRODUCT))
+
+# Find the device that this product maps to.
+TARGET_DEVICE := $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEVICE)
+
+# Figure out which resoure configuration options to use for this
+# product.
+PRODUCT_LOCALES := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_LOCALES))
+# TODO: also keep track of things like "port", "land" in product files.
+
+# If CUSTOM_LOCALES contains any locales not already included
+# in PRODUCT_LOCALES, add them to PRODUCT_LOCALES.
+extra_locales := $(filter-out $(PRODUCT_LOCALES),$(CUSTOM_LOCALES))
+ifneq (,$(extra_locales))
+  ifneq ($(CALLED_FROM_SETUP),true)
+    # Don't spam stdout, because envsetup.sh may be scraping values from it.
+    $(info Adding CUSTOM_LOCALES [$(extra_locales)] to PRODUCT_LOCALES [$(PRODUCT_LOCALES)])
+  endif
+  PRODUCT_LOCALES += $(extra_locales)
+  extra_locales :=
+endif
+
+# Default to medium-density assets.
+# (Can be overridden in the device config, e.g.: PRODUCT_LOCALES += hdpi)
+PRODUCT_LOCALES := $(strip \
+       $(PRODUCT_LOCALES) \
+       $(if $(filter %dpi,$(PRODUCT_LOCALES)),,mdpi))
+
+# Everyone gets nodpi assets which are density-independent.
+PRODUCT_LOCALES += nodpi
+
+# Assemble the list of options.
+PRODUCT_AAPT_CONFIG := $(PRODUCT_LOCALES)
+
+# Convert spaces to commas.
+comma := ,
+PRODUCT_AAPT_CONFIG := \
+       $(subst $(space),$(comma),$(strip $(PRODUCT_AAPT_CONFIG)))
+
+PRODUCT_BRAND := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_BRAND))
+
+PRODUCT_MODEL := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_MODEL))
+ifndef PRODUCT_MODEL
+  PRODUCT_MODEL := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_NAME))
+endif
+
+PRODUCT_MANUFACTURER := \
+       $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_MANUFACTURER))
+ifndef PRODUCT_MANUFACTURER
+  PRODUCT_MANUFACTURER := unknown
+endif
+
+ifeq ($(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_CHARACTERISTICS),)
+  TARGET_AAPT_CHARACTERISTICS := default
+else
+  TARGET_AAPT_CHARACTERISTICS := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_CHARACTERISTICS))
+endif
+
+PRODUCT_DEFAULT_WIFI_CHANNELS := \
+       $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEFAULT_WIFI_CHANNELS))
+
+# A list of words like <source path>:<destination path>.  The file at
+# the source path should be copied to the destination path when building
+# this product.  <destination path> is relative to $(PRODUCT_OUT), so
+# it should look like, e.g., "system/etc/file.xml".  The rules
+# for these copy steps are defined in config/Makefile.
+PRODUCT_COPY_FILES := \
+       $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_COPY_FILES))
+
+# The HTML file containing the contributors to the project.
+PRODUCT_CONTRIBUTORS_FILE := \
+       $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_CONTRIBUTORS_FILE))
+
+# A list of property assignments, like "key = value", with zero or more
+# whitespace characters on either side of the '='.
+PRODUCT_PROPERTY_OVERRIDES := \
+       $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PROPERTY_OVERRIDES))
+
+# Should we use the default resources or add any product specific overlays
+PRODUCT_PACKAGE_OVERLAYS := \
+       $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGE_OVERLAYS))
+DEVICE_PACKAGE_OVERLAYS := \
+        $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).DEVICE_PACKAGE_OVERLAYS))
+
+# An list of whitespace-separated words.
+PRODUCT_TAGS := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_TAGS))
+
+# Add the product-defined properties to the build properties.
+ADDITIONAL_BUILD_PROPERTIES := \
+       $(ADDITIONAL_BUILD_PROPERTIES) \
+       $(PRODUCT_PROPERTY_OVERRIDES)
+
+# The OTA key(s) specified by the product config, if any.  The names
+# of these keys are stored in the target-files zip so that post-build
+# signing tools can substitute them for the test key embedded by
+# default.
+PRODUCT_OTA_PUBLIC_KEYS := $(sort \
+    $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_OTA_PUBLIC_KEYS))
+
+# ---------------------------------------------------------------
+# Simulator overrides
+ifeq ($(TARGET_PRODUCT),sim)
+  # Tell the build system to turn on some special cases
+  # to deal with the simulator product.
+  TARGET_SIMULATOR := true
+  # dexpreopt doesn't work when building the simulator
+  DISABLE_DEXPREOPT := true
+endif
diff --git a/build/core/proguard.flags b/build/core/proguard.flags
new file mode 100644 (file)
index 0000000..447e7c5
--- /dev/null
@@ -0,0 +1,73 @@
+# see http://sourceforge.net/tracker/?func=detail&aid=2787465&group_id=54750&atid=474707
+-optimizations !code/simplification/arithmetic
+-optimizations !code/simplification/cast
+-allowaccessmodification
+
+# To prevent name conflict in incremental obfuscation.
+-useuniqueclassmembernames
+
+# dex does not like code run through proguard optimize and preverify steps.
+-dontoptimize
+-dontpreverify
+
+# Don't obfuscate. We only need dead code striping.
+-dontobfuscate
+
+# Add this flag in your package's own configuration if it's needed.
+#-flattenpackagehierarchy
+
+# Some classes in the libraries extend package private classes to chare common functionality
+# that isn't explicitly part of the API
+-dontskipnonpubliclibraryclasses -dontskipnonpubliclibraryclassmembers
+
+# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
+-keepclassmembers enum * {
+    public static **[] values();
+    public static ** valueOf(java.lang.String);
+}
+
+# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
+-keepclasseswithmembernames class * {
+    native <methods>;
+}
+
+# class$ methods are inserted by some compilers to implement .class construct,
+# see http://proguard.sourceforge.net/manual/examples.html#library
+-keepclassmembernames class * {
+    java.lang.Class class$(java.lang.String);
+    java.lang.Class class$(java.lang.String, boolean);
+}
+
+# Keep classes and methods that have the guava @VisibleForTesting annotation
+-keep @com.google.common.annotations.VisibleForTesting class *
+-keepclassmembers class * {
+@com.google.common.annotations.VisibleForTesting *;
+}
+
+# Keep serializable classes and necessary members for serializable classes
+# Copied from the ProGuard manual at http://proguard.sourceforge.net.
+-keepnames class * implements java.io.Serializable
+-keepclassmembers class * implements java.io.Serializable {
+    static final long serialVersionUID;
+    private static final java.io.ObjectStreamField[] serialPersistentFields;
+    !static !transient <fields>;
+    private void writeObject(java.io.ObjectOutputStream);
+    private void readObject(java.io.ObjectInputStream);
+    java.lang.Object writeReplace();
+    java.lang.Object readResolve();
+}
+
+# Please specify classes to be kept explicitly in your package's configuration.
+# -keep class * extends android.app.Activity
+# -keep class * extends android.view.View
+# -keep class * extends android.app.Service
+# -keep class * extends android.content.BroadcastReceiver
+# -keep class * extends android.content.ContentProvider
+# -keep class * extends android.preference.Preference
+# -keep class * extends android.app.BackupAgent
+
+#-keep class * implements android.os.Parcelable {
+#  public static final android.os.Parcelable$Creator *;
+#}
+
+
diff --git a/build/core/proguard_tests.flags b/build/core/proguard_tests.flags
new file mode 100644 (file)
index 0000000..f4063d6
--- /dev/null
@@ -0,0 +1,21 @@
+# Keep everything for tests
+-dontshrink -dontobfuscate
+
+#-keep class * extends junit.framework.TestCase {
+#  public void test*();
+#}
+
+#-keepclasseswithmembers class * {
+#  public static void run();
+#  public static junit.framework.Test suite();
+#}
+
+# some AllTests don't include run().
+#-keepclasseswithmembers class * {
+#  public static junit.framework.Test suite();
+#}
+
+#-keep class * extends junit.framework.TestSuite
+#-keep class * extends android.app.Instrumentation
+#-keep class * extends android.test.TestSuiteProvider
+
diff --git a/build/core/raw_executable.mk b/build/core/raw_executable.mk
new file mode 100644 (file)
index 0000000..b64173a
--- /dev/null
@@ -0,0 +1,25 @@
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_SUFFIX := 
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+
+include $(BUILD_SYSTEM)/binary.mk
+
+$(LOCAL_BUILT_MODULE) : PRIVATE_ELF_FILE := $(intermediates)/$(PRIVATE_MODULE).elf
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIBS := `$(TARGET_CC) -mthumb-interwork -print-libgcc-file-name`
+
+$(all_objects) : PRIVATE_TARGET_PROJECT_INCLUDES :=
+$(all_objects) : PRIVATE_TARGET_C_INCLUDES :=
+$(all_objects) : PRIVATE_TARGET_GLOBAL_CFLAGS :=
+$(all_objects) : PRIVATE_TARGET_GLOBAL_CPPFLAGS :=
+
+$(LOCAL_BUILT_MODULE): $(all_objects) $(all_libraries)
+       @$(mkdir -p $(dir $@)
+       @echo "target Linking: $(PRIVATE_MODULE)"
+       $(hide) $(TARGET_LD) \
+               $(addprefix --script ,$(PRIVATE_LINK_SCRIPT)) \
+               $(PRIVATE_RAW_EXECUTABLE_LDFLAGS) \
+               -o $(PRIVATE_ELF_FILE) \
+               $(PRIVATE_ALL_OBJECTS) \
+               --start-group $(PRIVATE_ALL_STATIC_LIBRARIES) --end-group \
+               $(PRIVATE_LIBS)
+       $(hide) $(TARGET_OBJCOPY) -O binary $(PRIVATE_ELF_FILE) $@
diff --git a/build/core/raw_static_library.mk b/build/core/raw_static_library.mk
new file mode 100644 (file)
index 0000000..f7b11ef
--- /dev/null
@@ -0,0 +1,5 @@
+
+LOCAL_RAW_STATIC_LIBRARY:=true
+
+include $(BUILD_STATIC_LIBRARY)
+
diff --git a/build/core/root.mk b/build/core/root.mk
new file mode 100644 (file)
index 0000000..6c8f795
--- /dev/null
@@ -0,0 +1,3 @@
+### DO NOT EDIT THIS FILE ###
+include build/core/main.mk
+### DO NOT EDIT THIS FILE ###
diff --git a/build/core/shared_library.mk b/build/core/shared_library.mk
new file mode 100644 (file)
index 0000000..77d253f
--- /dev/null
@@ -0,0 +1,54 @@
+###########################################################
+## Standard rules for building a normal shared library.
+##
+## Additional inputs from base_rules.make:
+## None.
+##
+## LOCAL_MODULE_SUFFIX will be set for you.
+###########################################################
+
+ifeq ($(strip $(LOCAL_MODULE_CLASS)),)
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+endif
+ifeq ($(strip $(LOCAL_MODULE_SUFFIX)),)
+LOCAL_MODULE_SUFFIX := $(TARGET_SHLIB_SUFFIX)
+endif
+ifeq ($(strip $(LOCAL_PRELINK_MODULE)),)
+LOCAL_PRELINK_MODULE := $(strip $(TARGET_PRELINK_MODULE))
+endif
+ifneq ($(strip $(OVERRIDE_BUILT_MODULE_PATH)),)
+$(error $(LOCAL_PATH): Illegal use of OVERRIDE_BUILT_MODULE_PATH)
+endif
+
+# Put the built targets of all shared libraries in a common directory
+# to simplify the link line.
+OVERRIDE_BUILT_MODULE_PATH := $(TARGET_OUT_INTERMEDIATE_LIBRARIES)
+
+include $(BUILD_SYSTEM)/dynamic_binary.mk
+
+# Define PRIVATE_ variables from global vars
+my_target_global_ld_dirs := $(TARGET_GLOBAL_LD_DIRS)
+my_target_global_ldflags := $(TARGET_GLOBAL_LDFLAGS)
+my_target_fdo_lib := $(TARGET_FDO_LIB)
+my_target_libgcc := $(TARGET_LIBGCC)
+my_target_crtbegin_so_o := $(TARGET_CRTBEGIN_SO_O)
+my_target_crtend_so_o := $(TARGET_CRTEND_SO_O)
+ifdef LOCAL_NDK_VERSION
+my_target_global_ld_dirs += -L$(my_ndk_version_root)/usr/lib
+# The latest ndk does NOT support TARGET_CRTBEGIN_SO_O and TARGET_CRTEND_SO_O yet.
+# my_target_crtbegin_so_o := $(my_ndk_version_root)/usr/lib/crtbegin_so.o
+# my_target_crtend_so_o := $(my_ndk_version_root)/usr/lib/crtend_so.o
+my_target_crtbegin_so_o :=
+my_target_crtend_so_o :=
+endif
+$(linked_module): PRIVATE_TARGET_GLOBAL_LD_DIRS := $(my_target_global_ld_dirs)
+$(linked_module): PRIVATE_TARGET_GLOBAL_LDFLAGS := $(my_target_global_ldflags)
+$(linked_module): PRIVATE_TARGET_FDO_LIB := $(my_target_fdo_lib)
+$(linked_module): PRIVATE_TARGET_LIBGCC := $(my_target_libgcc)
+$(linked_module): PRIVATE_TARGET_CRTBEGIN_SO_O := $(my_target_crtbegin_so_o)
+$(linked_module): PRIVATE_TARGET_CRTEND_SO_O := $(my_target_crtend_so_o)
+
+$(linked_module): $(all_objects) $(all_libraries) \
+                  $(LOCAL_ADDITIONAL_DEPENDENCIES) \
+                  $(my_target_crtbegin_so_o) $(my_target_crtend_so_o)
+       $(transform-o-to-shared-lib)
diff --git a/build/core/static_java_library.mk b/build/core/static_java_library.mk
new file mode 100644 (file)
index 0000000..93d770a
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Standard rules for building a "static" java library.
+# Static java libraries are not installed, nor listed on any
+# classpaths.  They can, however, be included wholesale in
+# other java modules.
+
+LOCAL_UNINSTALLABLE_MODULE := true
+LOCAL_IS_STATIC_JAVA_LIBRARY := true
+include $(BUILD_SYSTEM)/java_library.mk
+LOCAL_IS_STATIC_JAVA_LIBRARY :=
diff --git a/build/core/static_library.mk b/build/core/static_library.mk
new file mode 100644 (file)
index 0000000..4ff5a34
--- /dev/null
@@ -0,0 +1,30 @@
+###########################################################
+## Standard rules for building a static library.
+##
+## Additional inputs from base_rules.make:
+## None.
+##
+## LOCAL_MODULE_SUFFIX will be set for you.
+###########################################################
+
+ifeq ($(strip $(LOCAL_MODULE_CLASS)),)
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+endif
+ifeq ($(strip $(LOCAL_MODULE_SUFFIX)),)
+LOCAL_MODULE_SUFFIX := .a
+endif
+LOCAL_UNINSTALLABLE_MODULE := true
+
+include $(BUILD_SYSTEM)/binary.mk
+
+ifeq ($(LOCAL_RAW_STATIC_LIBRARY),true)
+LOCAL_RAW_STATIC_LIBRARY:=
+$(all_objects) : PRIVATE_TARGET_PROJECT_INCLUDES :=
+$(all_objects) : PRIVATE_TARGET_C_INCLUDES :=
+$(all_objects) : PRIVATE_TARGET_GLOBAL_CFLAGS :=
+$(all_objects) : PRIVATE_TARGET_GLOBAL_CPPFLAGS :=
+endif
+
+$(LOCAL_BUILT_MODULE): $(built_whole_libraries)
+$(LOCAL_BUILT_MODULE): $(all_objects)
+       $(transform-o-to-static-lib)
diff --git a/build/core/tasks/apicheck.mk b/build/core/tasks/apicheck.mk
new file mode 100644 (file)
index 0000000..740668c
--- /dev/null
@@ -0,0 +1,81 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Rules for running apicheck to confirm that you haven't broken
+# api compatibility or added apis illegally.
+#
+
+ifneq ($(BUILD_TINY_ANDROID), true)
+
+.PHONY: checkapi
+
+# eval this to define a rule that runs apicheck.
+#
+# Args:
+#    $(1)  target
+#    $(2)  stable api xml file
+#    $(3)  api xml file to be tested
+#    $(4)  arguments for apicheck
+#    $(5)  command to run if apicheck failed
+define check-api
+$(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/$(strip $(1))-timestamp: $(2) $(3) $(APICHECK)
+       @echo "Checking API:" $(1)
+       $(hide) ( $(APICHECK) $(4) $(2) $(3) || ( $(5) ; exit 38 ) )
+       $(hide) mkdir -p $$(dir $$@)
+       $(hide) touch $$@
+checkapi: $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/$(strip $(1))-timestamp
+endef
+
+# Run the checkapi rules by default.
+droidcore: checkapi
+
+last_released_sdk_version := $(lastword $(call numerically_sort,\
+    $(patsubst $(SRC_API_DIR)/%.xml,%, \
+    $(filter-out $(SRC_API_DIR)/current.xml, \
+    $(wildcard $(SRC_API_DIR)/*.xml)))))
+
+# INTERNAL_PLATFORM_API_FILE is the one build by droiddoc.
+
+# Check that the API we're building hasn't broken the last-released
+# SDK version.
+$(eval $(call check-api, \
+       checkapi-last, \
+       $(SRC_API_DIR)/$(last_released_sdk_version).xml, \
+       $(INTERNAL_PLATFORM_API_FILE), \
+       -hide 2 -hide 3 -hide 4 -hide 5 -hide 6 -hide 24 -hide 25 \
+       -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
+       -error 16 -error 17 -error 18 , \
+       cat $(BUILD_SYSTEM)/apicheck_msg_last.txt \
+       ))
+
+# Check that the API we're building hasn't changed from the not-yet-released
+# SDK version.
+$(eval $(call check-api, \
+       checkapi-current, \
+       $(SRC_API_DIR)/current.xml, \
+       $(INTERNAL_PLATFORM_API_FILE), \
+       -error 2 -error 3 -error 4 -error 5 -error 6 \
+       -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
+       -error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 \
+       -error 25 , \
+       cat $(BUILD_SYSTEM)/apicheck_msg_current.txt \
+       ))
+
+.PHONY: update-api
+update-api: $(INTERNAL_PLATFORM_API_FILE) | $(ACP)
+       @echo Copying current.xml
+       $(hide) $(ACP) $(INTERNAL_PLATFORM_API_FILE) $(SRC_API_DIR)/current.xml
+
+endif
diff --git a/build/core/tasks/cts.mk b/build/core/tasks/cts.mk
new file mode 100644 (file)
index 0000000..8c36ef6
--- /dev/null
@@ -0,0 +1,180 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+cts_dir := $(HOST_OUT)/cts
+cts_tools_src_dir := cts/tools
+
+cts_name := android-cts
+
+CTS_EXECUTABLE := startcts
+ifeq ($(HOST_OS),windows)
+    CTS_EXECUTABLE_PATH := $(cts_tools_src_dir)/host/etc/cts.bat
+else
+    CTS_EXECUTABLE_PATH := $(cts_tools_src_dir)/utils/$(CTS_EXECUTABLE)
+endif
+CTS_HOST_JAR := $(HOST_OUT_JAVA_LIBRARIES)/cts.jar
+
+DDMLIB_JAR := $(HOST_OUT_JAVA_LIBRARIES)/ddmlib-prebuilt.jar
+junit_host_jar := $(HOST_OUT_JAVA_LIBRARIES)/junit.jar
+HOSTTESTLIB_JAR := $(HOST_OUT_JAVA_LIBRARIES)/hosttestlib.jar
+
+CTS_CORE_CASE_LIST := \
+       android.core.tests.dom \
+       android.core.tests.luni.io \
+       android.core.tests.luni.lang \
+       android.core.tests.luni.net \
+       android.core.tests.luni.util \
+       android.core.tests.xml \
+       android.core.tests.runner
+
+-include cts/CtsTestCaseList.mk
+CTS_CASE_LIST := $(CTS_CORE_CASE_LIST) $(CTS_TEST_CASE_LIST)
+
+DEFAULT_TEST_PLAN := $(PRIVATE_DIR)/resource/plans
+
+$(cts_dir)/all_cts_files_stamp: PRIVATE_JUNIT_HOST_JAR := $(junit_host_jar)
+
+-include cts/CtsHostLibraryList.mk
+$(cts_dir)/all_cts_files_stamp: $(CTS_CASE_LIST) $(junit_host_jar) $(HOSTTESTLIB_JAR) $(CTS_HOST_LIBRARY_JARS) $(ACP)
+# Make necessary directory for CTS
+       @rm -rf $(PRIVATE_CTS_DIR)
+       @mkdir -p $(TMP_DIR)
+       @mkdir -p $(PRIVATE_DIR)/docs
+       @mkdir -p $(PRIVATE_DIR)/tools
+       @mkdir -p $(PRIVATE_DIR)/repository/testcases
+       @mkdir -p $(PRIVATE_DIR)/repository/plans
+# Copy executable and JARs to CTS directory
+       $(hide) $(ACP) -fp $(CTS_HOST_JAR) $(CTS_EXECUTABLE_PATH) $(DDMLIB_JAR) $(PRIVATE_JUNIT_HOST_JAR) $(HOSTTESTLIB_JAR) $(CTS_HOST_LIBRARY_JARS) $(PRIVATE_DIR)/tools
+# Change mode of the executables
+       $(hide) chmod ug+rwX $(PRIVATE_DIR)/tools/$(notdir $(CTS_EXECUTABLE_PATH))
+       $(foreach apk,$(CTS_CASE_LIST), \
+                       $(call copy-testcase-apk,$(apk)))
+# Copy CTS host config to CTS directory
+       $(hide) $(ACP) -fp $(cts_tools_src_dir)/utils/host_config.xml $(PRIVATE_DIR)/repository/
+       $(hide) touch $@
+
+# Generate the test descriptions for the core-tests
+# Parameters:
+# $1 : The output file where the description should be written (without the '.xml' extension)
+# $2 : The AndroidManifest.xml corresponding to the test package
+# $3 : The name of the TestSuite generator class to use
+# $4 : The directory containing vogar expectations files
+# $5 : The Android.mk corresponding to the test package (required for host-side tests only)
+define generate-core-test-description
+@echo "Generate core-test description ("$(notdir $(1))")"
+$(hide) java $(PRIVATE_JAVAOPTS) \
+       -classpath $(PRIVATE_CLASSPATH) \
+       $(PRIVATE_PARAMS) CollectAllTests $(1) \
+       $(2) $(3) $(4) $(5)
+endef
+
+CORE_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,core,,COMMON)
+JUNIT_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,core-junit,,COMMON)
+RUNNER_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,core-junitrunner,,COMMON)
+SUPPORT_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,core-tests-support,,COMMON)
+DOM_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,core-tests-dom,,COMMON)
+XML_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,core-tests-xml,,COMMON)
+TESTS_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,core-tests,,COMMON)
+GEN_CLASSPATH := $(CORE_INTERMEDIATES)/classes.jar:$(JUNIT_INTERMEDIATES)/classes.jar:$(RUNNER_INTERMEDIATES)/classes.jar:$(SUPPORT_INTERMEDIATES)/classes.jar:$(DOM_INTERMEDIATES)/classes.jar:$(XML_INTERMEDIATES)/classes.jar:$(TESTS_INTERMEDIATES)/classes.jar:$(CORE_INTERMEDIATES)/javalib.jar:$(JUNIT_INTERMEDIATES)/javalib.jar:$(RUNNER_INTERMEDIATES)/javalib.jar:$(SUPPORT_INTERMEDIATES)/javalib.jar:$(DOM_INTERMEDIATES)/javalib.jar:$(XML_INTERMEDIATES)/javalib.jar:$(TESTS_INTERMEDIATES)/javalib.jar:$(HOST_OUT_JAVA_LIBRARIES)/descGen.jar:$(HOST_JDK_TOOLS_JAR)
+
+$(cts_dir)/all_cts_core_files_stamp: PRIVATE_CLASSPATH:=$(GEN_CLASSPATH)
+$(cts_dir)/all_cts_core_files_stamp: PRIVATE_JAVAOPTS:=-Xmx256M
+$(cts_dir)/all_cts_core_files_stamp: PRIVATE_PARAMS:=-Dcts.useSuppliedTestResult=true
+$(cts_dir)/all_cts_core_files_stamp: PRIVATE_PARAMS+=-Dcts.useEnhancedJunit=true
+# Why does this depend on javalib.jar instead of classes.jar?  Because
+# even though the tool will operate on the classes.jar files, the
+# build system requires that dependencies use javalib.jar.  If
+# javalib.jar is up-to-date, then classes.jar is as well.  Depending
+# on classes.jar will build the files incorrectly.
+$(cts_dir)/all_cts_core_files_stamp: $(CTS_CORE_CASE_LIST) $(HOST_OUT_JAVA_LIBRARIES)/descGen.jar $(CORE_INTERMEDIATES)/javalib.jar $(JUNIT_INTERMEDIATES)/javalib.jar $(RUNNER_INTERMEDIATES)/javalib.jar $(SUPPORT_INTERMEDIATES)/javalib.jar $(DOM_INTERMEDIATES)/javalib.jar $(XML_INTERMEDIATES)/javalib.jar $(TESTS_INTERMEDIATES)/javalib.jar $(cts_dir)/all_cts_files_stamp | $(ACP)
+       $(call generate-core-test-description,$(cts_dir)/$(cts_name)/repository/testcases/android.core.tests.dom,\
+               cts/tests/core/dom/AndroidManifest.xml,\
+               tests.dom.AllTests, libcore/expectations)
+       $(call generate-core-test-description,$(cts_dir)/$(cts_name)/repository/testcases/android.core.tests.luni.io,\
+               cts/tests/core/luni-io/AndroidManifest.xml,\
+               tests.luni.AllTestsIo, libcore/expectations)
+       $(call generate-core-test-description,$(cts_dir)/$(cts_name)/repository/testcases/android.core.tests.luni.lang,\
+               cts/tests/core/luni-lang/AndroidManifest.xml,\
+               tests.luni.AllTestsLang, libcore/expectations)
+       $(call generate-core-test-description,$(cts_dir)/$(cts_name)/repository/testcases/android.core.tests.luni.net,\
+               cts/tests/core/luni-net/AndroidManifest.xml,\
+               tests.luni.AllTestsNet, libcore/expectations)
+       $(call generate-core-test-description,$(cts_dir)/$(cts_name)/repository/testcases/android.core.tests.luni.util,\
+               cts/tests/core/luni-util/AndroidManifest.xml,\
+               tests.luni.AllTestsUtil, libcore/expectations)
+       $(call generate-core-test-description,$(cts_dir)/$(cts_name)/repository/testcases/android.core.tests.xml,\
+               cts/tests/core/xml/AndroidManifest.xml,\
+               tests.xml.AllTests, libcore/expectations)
+       $(hide) touch $@
+
+
+# ----- Generate the test descriptions for the vm-tests -----
+#
+CORE_VM_TEST_DESC := $(cts_dir)/$(cts_name)/repository/testcases/android.core.vm-tests
+
+VMTESTS_INTERMEDIATES :=$(call intermediates-dir-for,EXECUTABLES,vm-tests,1,)
+# core tests only needed to get hold of junit-framework-classes
+CORE_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,core,,COMMON)
+JUNIT_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,core-junit,,COMMON)
+RUNNER_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,core-junitrunner,,COMMON)
+TESTS_INTERMEDIATES :=$(call intermediates-dir-for,JAVA_LIBRARIES,core-tests,,COMMON)
+
+GEN_CLASSPATH := $(CORE_INTERMEDIATES)/classes.jar:$(JUNIT_INTERMEDIATES)/classes.jar:$(RUNNER_INTERMEDIATES)/classes.jar:$(TESTS_INTERMEDIATES)/classes.jar:$(VMTESTS_INTERMEDIATES)/android.core.vm-tests.jar:$(HOST_OUT_JAVA_LIBRARIES)/descGen.jar:$(HOSTTESTLIB_JAR):$(DDMLIB_JAR):$(HOST_JDK_TOOLS_JAR)
+
+$(CORE_VM_TEST_DESC): PRIVATE_CLASSPATH:=$(GEN_CLASSPATH)
+$(CORE_VM_TEST_DESC): PRIVATE_PARAMS:=-Dcts.useSuppliedTestResult=true
+$(CORE_VM_TEST_DESC): PRIVATE_PARAMS+=-Dcts.useEnhancedJunit=true
+$(CORE_VM_TEST_DESC): PRIVATE_JAVAOPTS:=-Xmx256M
+# Please see big comment above on why this line depends on javalib.jar instead of classes.jar
+$(CORE_VM_TEST_DESC): vm-tests $(HOST_OUT_JAVA_LIBRARIES)/descGen.jar $(CORE_INTERMEDIATES)/javalib.jar $(JUNIT_INTERMEDIATES)/javalib.jar $(RUNNER_INTERMEDIATES)/javalib.jar $(VMTESTS_INTERMEDIATES)/android.core.vm-tests.jar $(TESTS_INTERMEDIATES)/javalib.jar  $(HOSTTESTLIB_JAR) $(DDMLIB_JAR) $(cts_dir)/all_cts_files_stamp | $(ACP)
+       $(call generate-core-test-description,$(CORE_VM_TEST_DESC),\
+               cts/tests/vm-tests/AndroidManifest.xml,\
+               dot.junit.AllJunitHostTests, libcore/expectations, cts/tools/vm-tests/Android.mk)
+       $(ACP) -fv $(VMTESTS_INTERMEDIATES)/android.core.vm-tests.jar $(PRIVATE_DIR)/repository/testcases/android.core.vm-tests.jar
+
+# Move app security host-side tests to the repository
+APP_SECURITY_LIB := $(cts_dir)/$(cts_name)/repository/testcases/CtsAppSecurityTests.jar
+
+$(APP_SECURITY_LIB): $(HOST_OUT_JAVA_LIBRARIES)/CtsAppSecurityTests.jar $(cts_dir)/all_cts_files_stamp $(ACP)
+       $(ACP) -fv $(HOST_OUT_JAVA_LIBRARIES)/CtsAppSecurityTests.jar $(APP_SECURITY_LIB)
+
+# Generate the default test plan for User.
+# Usage: buildCts.py <testRoot> <ctsOutputDir> <tempDir> <androidRootDir> <docletPath>
+$(DEFAULT_TEST_PLAN): $(cts_dir)/all_cts_files_stamp $(cts_dir)/all_cts_core_files_stamp $(cts_tools_src_dir)/utils/buildCts.py $(CORE_VM_TEST_DESC) $(APP_SECURITY_LIB) $(HOST_OUT_JAVA_LIBRARIES)/descGen.jar
+       $(hide) $(cts_tools_src_dir)/utils/buildCts.py cts/tests/tests/ $(PRIVATE_DIR) $(TMP_DIR) \
+               $(TOP) $(HOST_OUT_JAVA_LIBRARIES)/descGen.jar
+
+# Package CTS and clean up.
+#
+# TODO:
+#   Pack cts.bat into the same zip file as well. See http://buganizer/issue?id=1656821 for more details
+INTERNAL_CTS_TARGET := $(cts_dir)/$(cts_name).zip
+$(INTERNAL_CTS_TARGET): PRIVATE_NAME := $(cts_name)
+$(INTERNAL_CTS_TARGET): PRIVATE_CTS_DIR := $(cts_dir)
+$(INTERNAL_CTS_TARGET): PRIVATE_DIR := $(cts_dir)/$(cts_name)
+$(INTERNAL_CTS_TARGET): TMP_DIR := $(cts_dir)/temp
+$(INTERNAL_CTS_TARGET): $(cts_dir)/all_cts_files_stamp $(DEFAULT_TEST_PLAN) $(CORE_VM_TEST_DESC)
+       @echo "Package CTS: $@"
+       $(hide) cd $(dir $@) && zip -rq $(notdir $@) $(PRIVATE_NAME)
+
+.PHONY: cts
+cts: $(INTERNAL_CTS_TARGET) adb
+$(call dist-for-goals,cts,$(INTERNAL_CTS_TARGET))
+
+define copy-testcase-apk
+
+$(hide) $(ACP) -fp $(call intermediates-dir-for,APPS,$(1))/package.apk \
+       $(PRIVATE_DIR)/repository/testcases/$(1).apk
+
+endef
diff --git a/build/core/tasks/ide.mk b/build/core/tasks/ide.mk
new file mode 100644 (file)
index 0000000..e557e60
--- /dev/null
@@ -0,0 +1,62 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+define filter-ide-goals
+$(strip $(filter $(1)-%,$(MAKECMDGOALS)))
+endef
+
+define filter-ide-modules
+$(strip $(subst -,$(space),$(patsubst $(1)-%,%,$(2))))
+endef
+
+# eclipse
+eclipse_project_goals := $(call filter-ide-goals,ECLIPSE)
+ifdef eclipse_project_goals
+  ifneq ($(words $(eclipse_project_goals)),1)
+    $(error Only one ECLIPSE- goal may be specified: $(eclipse_project_goals))
+  endif
+  eclipse_project_modules := $(call filter-ide-modules,ECLIPSE,$(eclipse_project_goals))
+
+  ifneq ($(filter lunch,$(eclipse_project_modules)),)
+    eclipse_project_modules := $(filter-out lunch,$(eclipse_project_modules))
+    installed_modules := $(foreach m,$(ALL_DEFAULT_INSTALLED_MODULES),\
+        $(INSTALLABLE_FILES.$(m).MODULE))
+    java_modules := $(foreach m,$(installed_modules),\
+        $(if $(filter JAVA_LIBRARIES APPS,$(ALL_MODULES.$(m).CLASS)),$(m),))
+    eclipse_project_modules := $(sort $(eclipse_project_modules) $(java_modules))
+  endif
+
+  source_paths := $(foreach m,$(eclipse_project_modules),$(ALL_MODULES.$(m).PATH)) \
+              $(foreach m,$(eclipse_project_modules),$(ALL_MODULES.$(m).INTERMEDIATE_SOURCE_DIR)) \
+              $(INTERNAL_SDK_SOURCE_DIRS)
+  source_paths := $(sort $(source_paths))
+
+.classpath: PRIVATE_MODULES := $(eclipse_project_modules)
+.classpath: PRIVATE_DIRS := $(source_paths)
+
+# the mess below with ./src tries to guess whether the src
+$(eclipse_project_goals): .classpath
+.classpath: FORCE
+       $(hide) echo Generating .classpath for eclipse
+       $(hide) echo '<classpath>' > $@
+       $(hide) for p in $(PRIVATE_DIRS) ; do \
+               echo -n '  <classpathentry kind="src" path="' >> $@ ; \
+               ( if [ -d $$p/src ] ; then echo -n $$p/src ; else echo -n $$p ; fi ) >> $@ ; \
+               echo '"/>' >> $@ ; \
+       done
+       $(hide) echo '</classpath>' >> $@
+endif
+
diff --git a/build/core/tasks/product-graph.mk b/build/core/tasks/product-graph.mk
new file mode 100644 (file)
index 0000000..6442252
--- /dev/null
@@ -0,0 +1,48 @@
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+products_pdf := $(OUT_DIR)/products.pdf
+products_graph := $(products_pdf:%.pdf=%.dot)
+
+$(products_graph):
+       @echo Product graph DOT: $@
+       $(hide) ( \
+               echo 'digraph {'; \
+               echo 'graph [ ratio=.5 ];'; \
+               $(foreach p,$(ALL_PRODUCTS), \
+                       $(foreach d,$(PRODUCTS.$(strip $(p)).INHERITS_FROM), \
+                       echo \"$(d)\" -\> \"$(p)\";)) \
+               $(foreach prod, \
+                       $(sort $(foreach p,$(ALL_PRODUCTS), \
+                               $(foreach d,$(PRODUCTS.$(strip $(p)).INHERITS_FROM), \
+                                       $(d))) \
+                               $(foreach p,$(ALL_PRODUCTS),$(p))), \
+                       echo \"$(prod)\" [ label=\"$(dir $(prod))\\n$(notdir $(prod))\"];) \
+               echo '}' \
+       ) > $@
+
+# This rule doesn't include any nodes that don't inherit from
+# anything or don't have anything inherit from them, to make the
+# graph more readable.  To add that, add this line to the rule
+# below:
+#              $(foreach p,$(ALL_PRODUCTS), echo \"$(p)\";) \
+
+$(products_pdf): $(products_graph)
+       @echo Product graph PDF: $@
+       dot -Tpdf -Nshape=box -o $@ $<
+
+product-graph: $(products_pdf)
+
diff --git a/build/core/tasks/sdk-addon.mk b/build/core/tasks/sdk-addon.mk
new file mode 100644 (file)
index 0000000..62adeee
--- /dev/null
@@ -0,0 +1,91 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# If they didn't define PRODUCT_SDK_ADDON_NAME, then we won't define
+# any of these rules.
+addon_name := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SDK_ADDON_NAME))
+ifneq ($(addon_name),)
+
+addon_dir_leaf := $(addon_name)-$(FILE_NAME_TAG)-$(INTERNAL_SDK_HOST_OS_NAME)
+
+intermediates := $(HOST_OUT_INTERMEDIATES)/SDK_ADDON/$(addon_name)_intermediates
+full_target := $(HOST_OUT_SDK_ADDON)/$(addon_dir_leaf).zip
+staging := $(intermediates)/$(addon_dir_leaf)
+
+sdk_addon_deps :=
+files_to_copy :=
+
+# Files that are built and then copied into the sdk-addon
+ifneq ($(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SDK_ADDON_COPY_MODULES)),)
+$(foreach cf,$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SDK_ADDON_COPY_MODULES), \
+  $(eval _src := $(call module-stubs-files,$(call word-colon,1,$(cf)))) \
+  $(if $(_src),,$(eval $(error Unknown or unlinkable module: $(call word-colon,1,$(cf)). Requested by $(INTERNAL_PRODUCT)))) \
+  $(eval _dest := $(call word-colon,2,$(cf))) \
+  $(eval files_to_copy += $(_src):$(_dest)) \
+ )
+endif
+
+# Files that are copied directly into the sdk-addon
+files_to_copy += $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SDK_ADDON_COPY_FILES)
+
+# All SDK add-ons have these files
+files_to_copy += \
+        $(BUILT_SYSTEMIMAGE):images/system.img \
+        $(BUILT_USERDATAIMAGE_TARGET):images/userdata.img \
+        $(BUILT_RAMDISK_TARGET):images/ramdisk.img \
+        $(target_notice_file_txt):images/NOTICE.txt
+
+# Generate rules to copy the requested files
+$(foreach cf,$(files_to_copy), \
+  $(eval _src := $(call word-colon,1,$(cf))) \
+  $(eval _dest := $(call append-path,$(staging),$(call word-colon,2,$(cf)))) \
+  $(eval $(call copy-one-file,$(_src),$(_dest))) \
+  $(eval sdk_addon_deps += $(_dest)) \
+ )
+
+# We don't know about all of the docs files, so depend on the timestamp for
+# that, and record the directory, and the packaging rule will just copy the
+# whole thing.
+doc_module := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SDK_ADDON_DOC_MODULE))
+ifneq ($(doc_module),)
+  doc_timestamp := $(call doc-timestamp-for, $(doc_module))
+  sdk_addon_deps += $(doc_timestamp)
+  $(full_target): PRIVATE_DOCS_DIR := $(OUT_DOCS)/$(doc_module)
+else
+  $(full_target): PRIVATE_DOCS_DIR :=
+endif
+
+$(full_target): PRIVATE_STAGING_DIR := $(staging)
+
+$(full_target): $(sdk_addon_deps) | $(ACP)
+       @echo Packaging SDK Addon: $@
+       $(hide) mkdir -p $(PRIVATE_STAGING_DIR)/docs/reference
+       $(hide) if [ -n "$(PRIVATE_DOCS_DIR)" ] ; then \
+           $(ACP) -r $(PRIVATE_DOCS_DIR)/* $(PRIVATE_STAGING_DIR)/docs/reference ;\
+         fi
+       $(hide) mkdir -p $(dir $@)
+       $(hide) ( F=$$(pwd)/$@ ; cd $(PRIVATE_STAGING_DIR)/.. && zip -rq $$F * )
+
+.PHONY: sdk_addon
+sdk_addon: $(full_target)
+
+$(call dist-for-goals, sdk_addon, $(full_target))
+
+else # addon_name
+ifneq ($(filter sdk_addon,$(MAKECMDGOALS)),)
+$(error Trying to build sdk_addon, but product '$(INTERNAL_PRODUCT)' does not define one)
+endif
+endif # addon_name
+
diff --git a/build/core/user_tags.mk b/build/core/user_tags.mk
new file mode 100644 (file)
index 0000000..3eade8a
--- /dev/null
@@ -0,0 +1,508 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This is the list of modules grandfathered to use a user tag
+
+# DO NOT ADD ANY NEW MODULE TO THIS FILE
+#
+# user modules are hard to control and audit and we don't want
+# to add any new such module in the system
+
+GRANDFATHERED_USER_MODULES :=
+
+-include vendor/google/user_tags.mk
+
+GRANDFATHERED_USER_MODULES += \
+       20-dns.conf \
+       95-configured \
+       aapt \
+       acp \
+       adb \
+       AdbWinApi \
+       AdbWinUsbApi \
+       adbd \
+       aidl \
+       am \
+       android \
+       android-common \
+       android.policy \
+       androidprefs \
+       android.test.runner \
+       ant \
+       antlr-2.7.7 \
+       anttasks \
+       apicheck \
+       apkcheck \
+       applypatch \
+       app_process \
+       apriori \
+       archquery \
+       asm-3.1 \
+       atree \
+       audio \
+       badblocks \
+       badblocks_host \
+       bb2sym \
+       bb_dump \
+       bbprof \
+       bison \
+       bluetoothd \
+       bmgr \
+       bootanimation \
+       brcm_patchram_plus \
+       bugreport \
+       cfassembler \
+       check_stack \
+       check_trace \
+       clearsilver \
+       cmu2nuance \
+       com.android.inputmethod.pinyin.lib \
+       com.android.phone.common \
+       commons-compress-1.0 \
+       copybit.qsd8k \
+       coverage \
+       cpufeatures \
+       cts \
+       CtsAppSecurityTests \
+       cts-dalvik-buildutil \
+       dasm \
+       dbus-daemon \
+       ddmlib \
+       ddmlibTests \
+       ddmlib-prebuilt \
+       ddms \
+       ddmuilib \
+       debuggerd \
+       descGen \
+       dexpreopt \
+       dex-tools \
+       dhcpcd \
+       dhcpcd.conf \
+       dhcpcd-run-hooks \
+       dictTest \
+       dnsmasq \
+       draw9patch \
+       droiddoc \
+       dumpeventlog \
+       dumpkey \
+       dump_regions \
+       dumpstate \
+       dumpsys \
+       dx-tests \
+       e2fsck \
+       e2fsck_host \
+       easymock \
+       edify \
+       emmalib \
+       emulator \
+       emulator-arm \
+       emulator-core \
+       emulator-elff \
+       emulator-hw \
+       emulator-memcheck \
+       emulator-tcg \
+       emulator-ui \
+       etc1tool \
+       eventanalyzer \
+       exc_dump \
+       fastboot \
+       framework \
+       FrameworkCoreHostTests \
+       frameworks-core-util-lib \
+       fsck_msdos \
+       fs_get_stats \
+       fw_bcm4329_apsta.bin \
+       fw_bcm4329.bin \
+       genext2fs \
+       gps.mahimahi \
+       gralloc.default \
+       gralloc.qsd8k \
+       groovy-all-1.7.0 \
+       grxmlcompile \
+       guava \
+       guavalib \
+       gzip \
+       hciattach \
+       hierarchyviewer \
+       hierarchyviewer1 \
+       hierarchyviewer2 \
+       hierarchyviewerlib \
+       hist_trace \
+       hosttestlib \
+       icudata \
+       idegen \
+       ime \
+       init \
+       input \
+       installd \
+       iptables \
+       ip-up-vpn \
+       iself \
+       isprelinked \
+       jarjar \
+       javax.obex \
+       jcommon-1.0.12 \
+       jdiff \
+       jdwpspy \
+       jfreechart-1.0.9 \
+       jfreechart-1.0.9-swt \
+       jsilver \
+       jsr305 \
+       jsr305lib \
+       junit \
+       jython \
+       kcm \
+       keystore \
+       kxml2-2.3.0 \
+       launch-wrapper \
+       layoutlib \
+       layoutlib_api \
+       layoutlib_create \
+       layoutlib_utils \
+       layoutopt \
+       liba2dp \
+       libabi \
+       libacc \
+       libandroid \
+       libandroid_runtime \
+       libandroid_servers \
+       libarity \
+       libastl \
+       libastl_host \
+       libaudio \
+       libaudioeffect_jni \
+       libaudioflinger \
+       libaudiointerface \
+       libaudiopolicy \
+       libaudiopolicybase \
+       libbinder \
+       libbluedroid \
+       libbluetooth \
+       libbluetoothd \
+       libbuiltinplugin \
+       libbundlewrapper \
+       libbz \
+       libc \
+       libcamera_client \
+       libcameraservice \
+       libcamerastub \
+       libc_common \
+       libchromium_net \
+       libc_nomalloc \
+       libctest \
+       libcutils \
+       libdb \
+       libdbus \
+       libdiskconfig \
+       libdiskconfig_host \
+       libdl \
+       libdrm1 \
+       libdrm1_jni \
+       libebl \
+       libebl_arm \
+       libebl_sh \
+       libedify \
+       libeffects \
+       libEGL \
+       libelf \
+       libelfcopy \
+       libESR_Portable \
+       libESR_Shared \
+       libETC1 \
+       libexif \
+       libext \
+       libext2fs \
+       libext2fs_host \
+       libext2_blkid \
+       libext2_blkid_host \
+       libext2_com_err \
+       libext2_com_err_host \
+       libext2_e2p \
+       libext2_e2p_host \
+       libext2_profile \
+       libext2_profile_host \
+       libext2_uuid \
+       libext2_uuid_host \
+       libfdlibm \
+       libfdlibm-host \
+       libFFTEm \
+       libfst \
+       libft2 \
+       libgdbus_static \
+       libgif \
+       libGLES_android \
+       libGLESv1_CM \
+       libGLESv2 \
+       libglib \
+       libglib_static \
+       libgui \
+       libhardware \
+       libhardware_legacy \
+       libhost \
+       libhyphenation \
+       libiprouteutil \
+       libiptc \
+       libjnigraphics \
+       libjni_latinime \
+       libjni_pinyinime \
+       libjpeg \
+       libjs \
+       liblinenoise \
+       libloc_api-rpc \
+       liblog \
+       libm \
+       libmedia \
+       libmedia_jni \
+       libmediaplayerservice \
+       libmincrypt \
+       libminui \
+       libminzip \
+       libmtdutils \
+       libmusicbundle \
+       libneo_cgi \
+       libneo_cs \
+       libneo_util \
+       libnetlink \
+       libnetutils \
+       libop \
+       libOpenSLES \
+       libopensles_helper \
+       libOpenSLESUT \
+       libpcap \
+       libpixelflinger \
+       libpixelflinger_armv6 \
+       libpixelflinger_static \
+       libpng \
+       libpopt \
+       libpower \
+       librecovery_ui_htc \
+       libreference-cdma-sms \
+       libreference-ril \
+       libreverb \
+       libreverbwrapper \
+       libril \
+       librpc \
+       librtp_jni \
+       libsafe_iop \
+       libSDL \
+       libSDLmain \
+       libsensorservice \
+       libskia \
+       libskiagl \
+       libsonivox \
+       libsoundpool \
+       libspeex \
+       libsqlite \
+       libsqlite3_android \
+       libSR_AcousticModels \
+       libSR_AcousticState \
+       libSR_AudioIn \
+       libSR_Core \
+       libsrec_jni \
+       libSR_EventLog \
+       libSR_G2P \
+       libSR_Grammar \
+       libSR_Nametag \
+       libSR_Recognizer \
+       libSR_Semproc \
+       libSR_Session \
+       libSR_Vocabulary \
+       libstagefright \
+       libstagefright_aacdec \
+       libstagefright_aacenc \
+       libstagefright_amrnb_common \
+       libstagefright_amrnbdec \
+       libstagefright_amrnbenc \
+       libstagefright_amrwbdec \
+       libstagefright_amrwbenc \
+       libstagefright_avc_common \
+       libstagefright_avcdec \
+       libstagefright_avcenc \
+       libstagefright_color_conversion \
+       libstagefright_enc_common \
+       libstagefright_foundation \
+       libstagefright_g711dec \
+       libstagefright_httplive \
+       libstagefrighthw \
+       libstagefright_id3 \
+       libstagefright_m4vh263dec \
+       libstagefright_m4vh263enc \
+       libstagefright_matroska \
+       libstagefright_mp3dec \
+       libstagefright_mpeg2ts \
+       libstagefright_omx \
+       libstagefright_rtsp \
+       libstagefright_vorbisdec \
+       libstagefright_vpxdec \
+       libstdc++ \
+       libstlport \
+       libstlport_static \
+       libstorage \
+       libsurfaceflinger \
+       libsurfaceflinger_client \
+       libsvoxpico \
+       libsystem_server \
+       libsysutils \
+       libthread_db \
+       libtinyxml \
+       libtomcrypt \
+       libtommath \
+       libttspico \
+       libttssynthproxy \
+       libui \
+       libunz \
+       libutil \
+       libutils \
+       libv8 \
+       libvisualizer \
+       libvorbisidec \
+       libvpx \
+       libwebcore \
+       libwpa_client \
+       libwrapsim \
+       libxml2 \
+       libxslt \
+       libzipfile \
+       lights.kraken \
+       lights.qsd8k \
+       line_endings \
+       linker \
+       localize \
+       logcat \
+       logwrapper \
+       lsd \
+       mahimahi-keypad.kcm \
+       make_cfst \
+       makedict \
+       make_ext4fs \
+       make_g2g \
+       makekeycodes \
+       make_ve_grammar \
+       mediaserver \
+       minigzip \
+       mkbootfs \
+       mkbootimg \
+       mke2fs \
+       mke2fs_host \
+       mksdcard \
+       mksnapshot \
+       mkstubs \
+       mkuserimg.sh \
+       mkyaffs2image \
+       monkey \
+       monkeyrunner \
+       MonkeyRunnerTest \
+       mtpd \
+       ndc \
+       netcfg \
+       netd \
+       network \
+       ninepatch \
+       oauth \
+       obbtool \
+       omx_tests \
+       org.eclipse.core.commands_3.4.0.I20080509-2000 \
+       org.eclipse.equinox.common_3.4.0.v20080421-2006 \
+       org.eclipse.jface_3.4.2.M20090107-0800 \
+       org-netbeans-api-visual \
+       org-openide-util \
+       osgi \
+       pand \
+       parseStringTest \
+       ping \
+       platform.xml \
+       pm \
+       post_trace \
+       pppd \
+       preload \
+       profile_pid \
+       profile_trace \
+       q2dm \
+       q2g \
+       qemu-android \
+       qwerty2.kcm \
+       qwerty.kcm \
+       racoon \
+       read_addr \
+       read_method \
+       read_pid \
+       read_trace \
+       resize2fs \
+       resize2fs_host \
+       rgb2565 \
+       rild \
+       rsg-generator \
+       run-as \
+       runtime \
+       schedtest \
+       screenshot2 \
+       sdcard \
+       sdklauncher \
+       sdklib \
+       sdkmanager \
+       sdkstats \
+       sdkuilib \
+       sdk_v4 \
+       sdk_v5 \
+       sdk_v6 \
+       sdk_v7 \
+       sdk_v8 \
+       sdptool \
+       service \
+       servicemanager \
+       services \
+       sh \
+       sig \
+       sig-check \
+       sig-create \
+       signapk \
+       signature-tools \
+       simg2img \
+       simulator \
+       soslim \
+       spec-progress \
+       sqlite3 \
+       stack_dump \
+       stringtemplate \
+       surfaceflinger \
+       svc \
+       swing-worker-1.1 \
+       swt \
+       system_server \
+       tc \
+       temp_layoutlib \
+       test_g2g \
+       test-progress \
+       test-progress-new \
+       test_swiarb \
+       test_zipfile \
+       toolbox \
+       traceview \
+       tune2fs \
+       tune2fs_host \
+       tuttle2.kcm \
+       uix \
+       usbtest \
+       vdc \
+       vm-tests \
+       vold \
+       wdsclient \
+       wpa_supplicant \
+       wpa_supplicant.conf \
+       xmlwriter \
+       yuv420sp2rgb \
+       zipalign
+
diff --git a/build/core/version_defaults.mk b/build/core/version_defaults.mk
new file mode 100644 (file)
index 0000000..5618d78
--- /dev/null
@@ -0,0 +1,99 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Handle various build version information.
+#
+# Guarantees that the following are defined:
+#     PLATFORM_VERSION
+#     PLATFORM_SDK_VERSION
+#     PLATFORM_VERSION_CODENAME
+#     DEFAULT_APP_TARGET_SDK
+#     BUILD_ID
+#     BUILD_NUMBER
+#
+
+# Look for an optional file containing overrides of the defaults,
+# but don't cry if we don't find it.  We could just use -include, but
+# the build.prop target also wants INTERNAL_BUILD_ID_MAKEFILE to be set
+# if the file exists.
+#
+INTERNAL_BUILD_ID_MAKEFILE := $(wildcard $(BUILD_SYSTEM)/build_id.mk)
+ifneq "" "$(INTERNAL_BUILD_ID_MAKEFILE)"
+  include $(INTERNAL_BUILD_ID_MAKEFILE)
+endif
+
+ifeq "" "$(PLATFORM_VERSION)"
+  # This is the canonical definition of the platform version,
+  # which is the version that we reveal to the end user.
+  # Update this value when the platform version changes (rather
+  # than overriding it somewhere else).  Can be an arbitrary string.
+  PLATFORM_VERSION := AOSP
+endif
+
+ifeq "" "$(PLATFORM_SDK_VERSION)"
+  # This is the canonical definition of the SDK version, which defines
+  # the set of APIs and functionality available in the platform.  It
+  # is a single integer that increases monotonically as updates to
+  # the SDK are released.  It should only be incremented when the APIs for
+  # the new release are frozen (so that developers don't write apps against
+  # intermediate builds).  During development, this number remains at the
+  # SDK version the branch is based on and PLATFORM_VERSION_CODENAME holds
+  # the code-name of the new development work.
+  PLATFORM_SDK_VERSION := 9
+endif
+
+ifeq "" "$(PLATFORM_VERSION_CODENAME)"
+  # This is the current development code-name, if the build is not a final
+  # release build.  If this is a final release build, it is simply "REL".
+  PLATFORM_VERSION_CODENAME := AOSP
+endif
+
+ifeq "" "$(DEFAULT_APP_TARGET_SDK)"
+  # This is the default minSdkVersion and targetSdkVersion to use for
+  # all .apks created by the build system.  It can be overridden by explicitly
+  # setting these in the .apk's AndroidManifest.xml.  It is either the code
+  # name of the development build or, if this is a release build, the official
+  # SDK version of this release.
+  ifeq "REL" "$(PLATFORM_VERSION_CODENAME)"
+    DEFAULT_APP_TARGET_SDK := $(PLATFORM_SDK_VERSION)
+  else
+    DEFAULT_APP_TARGET_SDK := $(PLATFORM_VERSION_CODENAME)
+  endif
+endif
+
+ifeq "" "$(BUILD_ID)"
+  # Used to signify special builds.  E.g., branches and/or releases,
+  # like "M5-RC7".  Can be an arbitrary string, but must be a single
+  # word and a valid file name.
+  #
+  # If there is no BUILD_ID set, make it obvious.
+  BUILD_ID := UNKNOWN
+endif
+
+ifeq "" "$(BUILD_NUMBER)"
+  # BUILD_NUMBER should be set to the source control value that
+  # represents the current state of the source code.  E.g., a
+  # perforce changelist number or a git hash.  Can be an arbitrary string
+  # (to allow for source control that uses something other than numbers),
+  # but must be a single word and a valid file name.
+  #
+  # If no BUILD_NUMBER is set, create a useful "I am an engineering build
+  # from this date/time" value.  Make it start with a non-digit so that
+  # anyone trying to parse it as an integer will probably get "0".
+  BUILD_NUMBER := eng.$(USER).$(shell date +%Y%m%d.%H%M%S)
+endif
+
diff --git a/build/envsetup.sh b/build/envsetup.sh
new file mode 100644 (file)
index 0000000..8289c82
--- /dev/null
@@ -0,0 +1,1099 @@
+function help() {
+cat <<EOF
+Invoke ". build/envsetup.sh" from your shell to add the following functions to your environment:
+- croot:   Changes directory to the top of the tree.
+- m:       Makes from the top of the tree.
+- mm:      Builds all of the modules in the current directory.
+- mmm:     Builds all of the modules in the supplied directories.
+- cgrep:   Greps on all local C/C++ files.
+- jgrep:   Greps on all local Java files.
+- resgrep: Greps on all local res/*.xml files.
+- godir:   Go to the directory containing a file.
+
+Look at the source to view more functions. The complete list is:
+EOF
+    T=$(gettop)
+    local A
+    A=""
+    for i in `cat $T/build/envsetup.sh | sed -n "/^function /s/function \([a-z_]*\).*/\1/p" | sort`; do
+      A="$A $i"
+    done
+    echo $A
+}
+
+# Get the value of a build variable as an absolute path.
+function get_abs_build_var()
+{
+    T=$(gettop)
+    if [ ! "$T" ]; then
+        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
+        return
+    fi
+    CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \
+      make --no-print-directory -C "$T" -f build/core/config.mk dumpvar-abs-$1
+}
+
+# Get the exact value of a build variable.
+function get_build_var()
+{
+    T=$(gettop)
+    if [ ! "$T" ]; then
+        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
+        return
+    fi
+    CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \
+      make --no-print-directory -C "$T" -f build/core/config.mk dumpvar-$1
+}
+
+# check to see if the supplied product is one we can build
+function check_product()
+{
+    T=$(gettop)
+    if [ ! "$T" ]; then
+        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
+        return
+    fi
+    CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \
+        TARGET_PRODUCT=$1 TARGET_BUILD_VARIANT= \
+        TARGET_SIMULATOR= TARGET_BUILD_TYPE= \
+        TARGET_BUILD_APPS= \
+        get_build_var TARGET_DEVICE > /dev/null
+    # hide successful answers, but allow the errors to show
+}
+
+VARIANT_CHOICES=(user userdebug eng)
+
+# check to see if the supplied variant is valid
+function check_variant()
+{
+    for v in ${VARIANT_CHOICES[@]}
+    do
+        if [ "$v" = "$1" ]
+        then
+            return 0
+        fi
+    done
+    return 1
+}
+
+function setpaths()
+{
+    T=$(gettop)
+    if [ ! "$T" ]; then
+        echo "Couldn't locate the top of the tree.  Try setting TOP."
+        return
+    fi
+
+    ##################################################################
+    #                                                                #
+    #              Read me before you modify this code               #
+    #                                                                #
+    #   This function sets ANDROID_BUILD_PATHS to what it is adding  #
+    #   to PATH, and the next time it is run, it removes that from   #
+    #   PATH.  This is required so lunch can be run more than once   #
+    #   and still have working paths.                                #
+    #                                                                #
+    ##################################################################
+
+    # out with the old
+    if [ -n $ANDROID_BUILD_PATHS ] ; then
+        export PATH=${PATH/$ANDROID_BUILD_PATHS/}
+    fi
+    if [ -n $ANDROID_PRE_BUILD_PATHS ] ; then
+        export PATH=${PATH/$ANDROID_PRE_BUILD_PATHS/}
+    fi
+
+    # and in with the new
+    CODE_REVIEWS=
+    prebuiltdir=$(getprebuilt)
+    export ANDROID_EABI_TOOLCHAIN=$prebuiltdir/toolchain/arm-eabi-4.4.3/bin
+    export ANDROID_TOOLCHAIN=$ANDROID_EABI_TOOLCHAIN
+    export ANDROID_QTOOLS=$T/development/emulator/qtools
+    export ANDROID_BUILD_PATHS=:$(get_build_var ANDROID_BUILD_PATHS):$ANDROID_QTOOLS:$ANDROID_TOOLCHAIN:$ANDROID_EABI_TOOLCHAIN$CODE_REVIEWS
+    export PATH=$PATH$ANDROID_BUILD_PATHS
+
+    unset ANDROID_JAVA_TOOLCHAIN
+    if [ -n "$JAVA_HOME" ]; then
+        export ANDROID_JAVA_TOOLCHAIN=$JAVA_HOME/bin
+    fi
+    export ANDROID_PRE_BUILD_PATHS=$ANDROID_JAVA_TOOLCHAIN
+    if [ -n "$ANDROID_PRE_BUILD_PATHS" ]; then
+        export PATH=$ANDROID_PRE_BUILD_PATHS:$PATH
+    fi
+
+    unset ANDROID_PRODUCT_OUT
+    export ANDROID_PRODUCT_OUT=$(get_abs_build_var PRODUCT_OUT)
+    export OUT=$ANDROID_PRODUCT_OUT
+
+    # needed for building linux on MacOS
+    # TODO: fix the path
+    #export HOST_EXTRACFLAGS="-I "$T/system/kernel_headers/host_include
+
+    # needed for OProfile to post-process collected samples
+    export OPROFILE_EVENTS_DIR=$prebuiltdir/oprofile
+}
+
+function printconfig()
+{
+    T=$(gettop)
+    if [ ! "$T" ]; then
+        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
+        return
+    fi
+    get_build_var report_config
+}
+
+function set_stuff_for_environment()
+{
+    settitle
+    set_java_home
+    setpaths
+    set_sequence_number
+
+    export ANDROID_BUILD_TOP=$(gettop)
+}
+
+function set_sequence_number()
+{
+    export BUILD_ENV_SEQUENCE_NUMBER=10
+}
+
+function settitle()
+{
+    if [ "$STAY_OFF_MY_LAWN" = "" ]; then
+        local product=$TARGET_PRODUCT
+        local variant=$TARGET_BUILD_VARIANT
+        local apps=$TARGET_BUILD_APPS
+        if [ -z "$apps" ]; then
+            export PROMPT_COMMAND="echo -ne \"\033]0;[${product}-${variant}] ${USER}@${HOSTNAME}: ${PWD}\007\""
+        else
+            export PROMPT_COMMAND="echo -ne \"\033]0;[$apps $variant] ${USER}@${HOSTNAME}: ${PWD}\007\""
+        fi
+    fi
+}
+
+case `uname -s` in
+    Linux)
+        function choosesim()
+        {
+            echo "Build for the simulator or the device?"
+            echo "     1. Device"
+            echo "     2. Simulator"
+            echo
+
+            export TARGET_SIMULATOR=
+            local ANSWER
+            while [ -z $TARGET_SIMULATOR ]
+            do
+                echo -n "Which would you like? [1] "
+                if [ -z "$1" ] ; then
+                    read ANSWER
+                else
+                    echo $1
+                    ANSWER=$1
+                fi
+                case $ANSWER in
+                "")
+                    export TARGET_SIMULATOR=false
+                    ;;
+                1)
+                    export TARGET_SIMULATOR=false
+                    ;;
+                Device)
+                    export TARGET_SIMULATOR=false
+                    ;;
+                2)
+                    export TARGET_SIMULATOR=true
+                    ;;
+                Simulator)
+                    export TARGET_SIMULATOR=true
+                    ;;
+                *)
+                    echo
+                    echo "I didn't understand your response.  Please try again."
+                    echo
+                    ;;
+                esac
+                if [ -n "$1" ] ; then
+                    break
+                fi
+            done
+
+            set_stuff_for_environment
+        }
+        ;;
+    *)
+        function choosesim()
+        {
+            echo "Only device builds are supported for" `uname -s`
+            echo "     Forcing TARGET_SIMULATOR=false"
+            echo
+            if [ -z "$1" ]
+            then
+                echo -n "Press enter: "
+                read
+            fi
+
+            export TARGET_SIMULATOR=false
+            set_stuff_for_environment
+        }
+        ;;
+esac
+
+function choosetype()
+{
+    echo "Build type choices are:"
+    echo "     1. release"
+    echo "     2. debug"
+    echo
+
+    local DEFAULT_NUM DEFAULT_VALUE
+    if [ $TARGET_SIMULATOR = "false" ] ; then
+        DEFAULT_NUM=1
+        DEFAULT_VALUE=release
+    else
+        DEFAULT_NUM=2
+        DEFAULT_VALUE=debug
+    fi
+
+    export TARGET_BUILD_TYPE=
+    local ANSWER
+    while [ -z $TARGET_BUILD_TYPE ]
+    do
+        echo -n "Which would you like? ["$DEFAULT_NUM"] "
+        if [ -z "$1" ] ; then
+            read ANSWER
+        else
+            echo $1
+            ANSWER=$1
+        fi
+        case $ANSWER in
+        "")
+            export TARGET_BUILD_TYPE=$DEFAULT_VALUE
+            ;;
+        1)
+            export TARGET_BUILD_TYPE=release
+            ;;
+        release)
+            export TARGET_BUILD_TYPE=release
+            ;;
+        2)
+            export TARGET_BUILD_TYPE=debug
+            ;;
+        debug)
+            export TARGET_BUILD_TYPE=debug
+            ;;
+        *)
+            echo
+            echo "I didn't understand your response.  Please try again."
+            echo
+            ;;
+        esac
+        if [ -n "$1" ] ; then
+            break
+        fi
+    done
+
+    set_stuff_for_environment
+}
+
+#
+# This function isn't really right:  It chooses a TARGET_PRODUCT
+# based on the list of boards.  Usually, that gets you something
+# that kinda works with a generic product, but really, you should
+# pick a product by name.
+#
+function chooseproduct()
+{
+    if [ "x$TARGET_PRODUCT" != x ] ; then
+        default_value=$TARGET_PRODUCT
+    else
+        if [ "$TARGET_SIMULATOR" = true ] ; then
+            default_value=sim
+        else
+            default_value=full
+        fi
+    fi
+
+    export TARGET_PRODUCT=
+    local ANSWER
+    while [ -z "$TARGET_PRODUCT" ]
+    do
+        echo -n "Which product would you like? [$default_value] "
+        if [ -z "$1" ] ; then
+            read ANSWER
+        else
+            echo $1
+            ANSWER=$1
+        fi
+
+        if [ -z "$ANSWER" ] ; then
+            export TARGET_PRODUCT=$default_value
+        else
+            if check_product $ANSWER
+            then
+                export TARGET_PRODUCT=$ANSWER
+            else
+                echo "** Not a valid product: $ANSWER"
+            fi
+        fi
+        if [ -n "$1" ] ; then
+            break
+        fi
+    done
+
+    set_stuff_for_environment
+}
+
+function choosevariant()
+{
+    echo "Variant choices are:"
+    local index=1
+    local v
+    for v in ${VARIANT_CHOICES[@]}
+    do
+        # The product name is the name of the directory containing
+        # the makefile we found, above.
+        echo "     $index. $v"
+        index=$(($index+1))
+    done
+
+    local default_value=eng
+    local ANSWER
+
+    export TARGET_BUILD_VARIANT=
+    while [ -z "$TARGET_BUILD_VARIANT" ]
+    do
+        echo -n "Which would you like? [$default_value] "
+        if [ -z "$1" ] ; then
+            read ANSWER
+        else
+            echo $1
+            ANSWER=$1
+        fi
+
+        if [ -z "$ANSWER" ] ; then
+            export TARGET_BUILD_VARIANT=$default_value
+        elif (echo -n $ANSWER | grep -q -e "^[0-9][0-9]*$") ; then
+            if [ "$ANSWER" -le "${#VARIANT_CHOICES[@]}" ] ; then
+                export TARGET_BUILD_VARIANT=${VARIANT_CHOICES[$(($ANSWER-1))]}
+            fi
+        else
+            if check_variant $ANSWER
+            then
+                export TARGET_BUILD_VARIANT=$ANSWER
+            else
+                echo "** Not a valid variant: $ANSWER"
+            fi
+        fi
+        if [ -n "$1" ] ; then
+            break
+        fi
+    done
+}
+
+function choosecombo()
+{
+    choosesim $1
+
+    echo
+    echo
+    choosetype $2
+
+    echo
+    echo
+    chooseproduct $3
+
+    echo
+    echo
+    choosevariant $4
+
+    echo
+    set_stuff_for_environment
+    printconfig
+}
+
+# Clear this variable.  It will be built up again when the vendorsetup.sh
+# files are included at the end of this file.
+unset LUNCH_MENU_CHOICES
+function add_lunch_combo()
+{
+    local new_combo=$1
+    local c
+    for c in ${LUNCH_MENU_CHOICES[@]} ; do
+        if [ "$new_combo" = "$c" ] ; then
+            return
+        fi
+    done
+    LUNCH_MENU_CHOICES=(${LUNCH_MENU_CHOICES[@]} $new_combo)
+}
+
+# add the default one here
+add_lunch_combo full-eng
+add_lunch_combo full_x86-eng
+
+# if we're on linux, add the simulator.  There is a special case
+# in lunch to deal with the simulator
+if [ "$(uname)" = "Linux" ] ; then
+    add_lunch_combo simulator
+fi
+
+function print_lunch_menu()
+{
+    local uname=$(uname)
+    echo
+    echo "You're building on" $uname
+    echo
+    echo "Lunch menu... pick a combo:"
+
+    local i=1
+    local choice
+    for choice in ${LUNCH_MENU_CHOICES[@]}
+    do
+        echo "     $i. $choice"
+        i=$(($i+1))
+    done
+
+    echo
+}
+
+function lunch()
+{
+    local answer
+
+    if [ "$1" ] ; then
+        answer=$1
+    else
+        print_lunch_menu
+        echo -n "Which would you like? [full-eng] "
+        read answer
+    fi
+
+    local selection=
+
+    if [ -z "$answer" ]
+    then
+        selection=full-eng
+    elif [ "$answer" = "simulator" ]
+    then
+        selection=simulator
+    elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$")
+    then
+        if [ $answer -le ${#LUNCH_MENU_CHOICES[@]} ]
+        then
+            selection=${LUNCH_MENU_CHOICES[$(($answer-1))]}
+        fi
+    elif (echo -n $answer | grep -q -e "^[^\-][^\-]*-[^\-][^\-]*$")
+    then
+        selection=$answer
+    fi
+
+    if [ -z "$selection" ]
+    then
+        echo
+        echo "Invalid lunch combo: $answer"
+        return 1
+    fi
+
+    export TARGET_BUILD_APPS=
+
+    # special case the simulator
+    if [ "$selection" = "simulator" ]
+    then
+        export TARGET_PRODUCT=sim
+        export TARGET_BUILD_VARIANT=eng
+        export TARGET_SIMULATOR=true
+        export TARGET_BUILD_TYPE=debug
+    else
+        local product=$(echo -n $selection | sed -e "s/-.*$//")
+        check_product $product
+        if [ $? -ne 0 ]
+        then
+            echo
+            echo "** Don't have a product spec for: '$product'"
+            echo "** Do you have the right repo manifest?"
+            product=
+        fi
+
+        local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//")
+        check_variant $variant
+        if [ $? -ne 0 ]
+        then
+            echo
+            echo "** Invalid variant: '$variant'"
+            echo "** Must be one of ${VARIANT_CHOICES[@]}"
+            variant=
+        fi
+
+        if [ -z "$product" -o -z "$variant" ]
+        then
+            echo
+            return 1
+        fi
+
+        export TARGET_PRODUCT=$product
+        export TARGET_BUILD_VARIANT=$variant
+        export TARGET_SIMULATOR=false
+        export TARGET_BUILD_TYPE=release
+    fi # !simulator
+
+    echo
+
+    set_stuff_for_environment
+    printconfig
+}
+
+# Configures the build to build unbundled apps.
+# Run tapas with one ore more app names (from LOCAL_PACKAGE_NAME)
+function tapas()
+{
+    local variant=$(echo -n $(echo $* | xargs -n 1 echo | grep -E '^(user|userdebug|eng)$'))
+    local apps=$(echo -n $(echo $* | xargs -n 1 echo | grep -E -v '^(user|userdebug|eng)$'))
+
+    if [ $(echo $variant | wc -w) -gt 1 ]; then
+        echo "tapas: Error: Multiple build variants supplied: $variant"
+        return
+    fi
+    if [ -z "$variant" ]; then
+        variant=eng
+    fi
+    if [ -z "$apps" ]; then
+        apps=all
+    fi
+
+    export TARGET_PRODUCT=full
+    export TARGET_BUILD_VARIANT=$variant
+    export TARGET_SIMULATOR=false
+    export TARGET_BUILD_TYPE=release
+    export TARGET_BUILD_APPS=$apps
+
+    set_stuff_for_environment
+    printconfig
+}
+
+function gettop
+{
+    local TOPFILE=build/core/envsetup.mk
+    if [ -n "$TOP" -a -f "$TOP/$TOPFILE" ] ; then
+        echo $TOP
+    else
+        if [ -f $TOPFILE ] ; then
+            # The following circumlocution (repeated below as well) ensures
+            # that we record the true directory name and not one that is
+            # faked up with symlink names.
+            PWD= /bin/pwd
+        else
+            # We redirect cd to /dev/null in case it's aliased to
+            # a command that prints something as a side-effect
+            # (like pushd)
+            local HERE=$PWD
+            T=
+            while [ \( ! \( -f $TOPFILE \) \) -a \( $PWD != "/" \) ]; do
+                cd .. > /dev/null
+                T=`PWD= /bin/pwd`
+            done
+            cd $HERE > /dev/null
+            if [ -f "$T/$TOPFILE" ]; then
+                echo $T
+            fi
+        fi
+    fi
+}
+
+function m()
+{
+    T=$(gettop)
+    if [ "$T" ]; then
+        make -C $T $@
+    else
+        echo "Couldn't locate the top of the tree.  Try setting TOP."
+    fi
+}
+
+function findmakefile()
+{
+    TOPFILE=build/core/envsetup.mk
+    # We redirect cd to /dev/null in case it's aliased to
+    # a command that prints something as a side-effect
+    # (like pushd)
+    local HERE=$PWD
+    T=
+    while [ \( ! \( -f $TOPFILE \) \) -a \( $PWD != "/" \) ]; do
+        T=$PWD
+        if [ -f "$T/Android.mk" ]; then
+            echo $T/Android.mk
+            cd $HERE > /dev/null
+            return
+        fi
+        cd .. > /dev/null
+    done
+    cd $HERE > /dev/null
+}
+
+function mm()
+{
+    # If we're sitting in the root of the build tree, just do a
+    # normal make.
+    if [ -f build/core/envsetup.mk -a -f Makefile ]; then
+        make $@
+    else
+        # Find the closest Android.mk file.
+        T=$(gettop)
+        local M=$(findmakefile)
+        # Remove the path to top as the makefilepath needs to be relative
+        local M=`echo $M|sed 's:'$T'/::'`
+        if [ ! "$T" ]; then
+            echo "Couldn't locate the top of the tree.  Try setting TOP."
+        elif [ ! "$M" ]; then
+            echo "Couldn't locate a makefile from the current directory."
+        else
+            ONE_SHOT_MAKEFILE=$M make -C $T all_modules $@
+        fi
+    fi
+}
+
+function mmm()
+{
+    T=$(gettop)
+    if [ "$T" ]; then
+        local MAKEFILE=
+        local ARGS=
+        local DIR TO_CHOP
+        local DASH_ARGS=$(echo "$@" | awk -v RS=" " -v ORS=" " '/^-.*$/')
+        local DIRS=$(echo "$@" | awk -v RS=" " -v ORS=" " '/^[^-].*$/')
+        for DIR in $DIRS ; do
+            DIR=`echo $DIR | sed -e 's:/$::'`
+            if [ -f $DIR/Android.mk ]; then
+                TO_CHOP=`(cd -P -- $T && pwd -P) | wc -c | tr -d ' '`
+                TO_CHOP=`expr $TO_CHOP + 1`
+                START=`PWD= /bin/pwd`
+                MFILE=`echo $START | cut -c${TO_CHOP}-`
+                if [ "$MFILE" = "" ] ; then
+                    MFILE=$DIR/Android.mk
+                else
+                    MFILE=$MFILE/$DIR/Android.mk
+                fi
+                MAKEFILE="$MAKEFILE $MFILE"
+            else
+                if [ "$DIR" = snod ]; then
+                    ARGS="$ARGS snod"
+                elif [ "$DIR" = showcommands ]; then
+                    ARGS="$ARGS showcommands"
+                elif [ "$DIR" = dist ]; then
+                    ARGS="$ARGS dist"
+                else
+                    echo "No Android.mk in $DIR."
+                    return 1
+                fi
+            fi
+        done
+        ONE_SHOT_MAKEFILE="$MAKEFILE" make -C $T $DASH_ARGS all_modules $ARGS
+    else
+        echo "Couldn't locate the top of the tree.  Try setting TOP."
+    fi
+}
+
+function croot()
+{
+    T=$(gettop)
+    if [ "$T" ]; then
+        cd $(gettop)
+    else
+        echo "Couldn't locate the top of the tree.  Try setting TOP."
+    fi
+}
+
+function cproj()
+{
+    TOPFILE=build/core/envsetup.mk
+    # We redirect cd to /dev/null in case it's aliased to
+    # a command that prints something as a side-effect
+    # (like pushd)
+    local HERE=$PWD
+    T=
+    while [ \( ! \( -f $TOPFILE \) \) -a \( $PWD != "/" \) ]; do
+        T=$PWD
+        if [ -f "$T/Android.mk" ]; then
+            cd $T
+            return
+        fi
+        cd .. > /dev/null
+    done
+    cd $HERE > /dev/null
+    echo "can't find Android.mk"
+}
+
+function pid()
+{
+   local EXE="$1"
+   if [ "$EXE" ] ; then
+       local PID=`adb shell ps | fgrep $1 | sed -e 's/[^ ]* *\([0-9]*\).*/\1/'`
+       echo "$PID"
+   else
+       echo "usage: pid name"
+   fi
+}
+
+# systemstack - dump the current stack trace of all threads in the system process
+# to the usual ANR traces file
+function systemstack()
+{
+    adb shell echo '""' '>>' /data/anr/traces.txt && adb shell chmod 776 /data/anr/traces.txt && adb shell kill -3 $(pid system_server)
+}
+
+function gdbclient()
+{
+   local OUT_ROOT=$(get_abs_build_var PRODUCT_OUT)
+   local OUT_SYMBOLS=$(get_abs_build_var TARGET_OUT_UNSTRIPPED)
+   local OUT_SO_SYMBOLS=$(get_abs_build_var TARGET_OUT_SHARED_LIBRARIES_UNSTRIPPED)
+   local OUT_EXE_SYMBOLS=$(get_abs_build_var TARGET_OUT_EXECUTABLES_UNSTRIPPED)
+   local PREBUILTS=$(get_abs_build_var ANDROID_PREBUILTS)
+   if [ "$OUT_ROOT" -a "$PREBUILTS" ]; then
+       local EXE="$1"
+       if [ "$EXE" ] ; then
+           EXE=$1
+       else
+           EXE="app_process"
+       fi
+
+       local PORT="$2"
+       if [ "$PORT" ] ; then
+           PORT=$2
+       else
+           PORT=":5039"
+       fi
+
+       local PID
+       local PROG="$3"
+       if [ "$PROG" ] ; then
+           PID=`pid $3`
+           adb forward "tcp$PORT" "tcp$PORT"
+           adb shell gdbserver $PORT --attach $PID &
+           sleep 2
+       else
+               echo ""
+               echo "If you haven't done so already, do this first on the device:"
+               echo "    gdbserver $PORT /system/bin/$EXE"
+                   echo " or"
+               echo "    gdbserver $PORT --attach $PID"
+               echo ""
+       fi
+
+       echo >|"$OUT_ROOT/gdbclient.cmds" "set solib-absolute-prefix $OUT_SYMBOLS"
+       echo >>"$OUT_ROOT/gdbclient.cmds" "set solib-search-path $OUT_SO_SYMBOLS"
+       echo >>"$OUT_ROOT/gdbclient.cmds" "target remote $PORT"
+       echo >>"$OUT_ROOT/gdbclient.cmds" ""
+
+       arm-eabi-gdb -x "$OUT_ROOT/gdbclient.cmds" "$OUT_EXE_SYMBOLS/$EXE"
+  else
+       echo "Unable to determine build system output dir."
+   fi
+
+}
+
+case `uname -s` in
+    Darwin)
+        function sgrep()
+        {
+            find -E . -type f -iregex '.*\.(c|h|cpp|S|java|xml|sh|mk)' -print0 | xargs -0 grep --color -n "$@"
+        }
+
+        ;;
+    *)
+        function sgrep()
+        {
+            find . -type f -iregex '.*\.\(c\|h\|cpp\|S\|java\|xml\|sh\|mk\)' -print0 | xargs -0 grep --color -n "$@"
+        }
+        ;;
+esac
+
+function jgrep()
+{
+    find . -type f -name "*\.java" -print0 | xargs -0 grep --color -n "$@"
+}
+
+function cgrep()
+{
+    find . -type f \( -name '*.c' -o -name '*.cc' -o -name '*.cpp' -o -name '*.h' \) -print0 | xargs -0 grep --color -n "$@"
+}
+
+function resgrep()
+{
+    for dir in `find . -name res -type d`; do find $dir -type f -name '*\.xml' -print0 | xargs -0 grep --color -n "$@"; done;
+}
+
+case `uname -s` in
+    Darwin)
+        function mgrep()
+        {
+            find -E . -type f -iregex '.*/(Makefile|Makefile\..*|.*\.make|.*\.mak|.*\.mk)' -print0 | xargs -0 grep --color -n "$@"
+        }
+
+        function treegrep()
+        {
+            find -E . -type f -iregex '.*\.(c|h|cpp|S|java|xml)' -print0 | xargs -0 grep --color -n -i "$@"
+        }
+
+        ;;
+    *)
+        function mgrep()
+        {
+            find . -regextype posix-egrep -iregex '(.*\/Makefile|.*\/Makefile\..*|.*\.make|.*\.mak|.*\.mk)' -type f -print0 | xargs -0 grep --color -n "$@"
+        }
+
+        function treegrep()
+        {
+            find . -regextype posix-egrep -iregex '.*\.(c|h|cpp|S|java|xml)' -type f -print0 | xargs -0 grep --color -n -i "$@"
+        }
+
+        ;;
+esac
+
+function getprebuilt
+{
+    get_abs_build_var ANDROID_PREBUILTS
+}
+
+function tracedmdump()
+{
+    T=$(gettop)
+    if [ ! "$T" ]; then
+        echo "Couldn't locate the top of the tree.  Try setting TOP."
+        return
+    fi
+    local prebuiltdir=$(getprebuilt)
+    local KERNEL=$T/prebuilt/android-arm/kernel/vmlinux-qemu
+
+    local TRACE=$1
+    if [ ! "$TRACE" ] ; then
+        echo "usage:  tracedmdump  tracename"
+        return
+    fi
+
+    if [ ! -r "$KERNEL" ] ; then
+        echo "Error: cannot find kernel: '$KERNEL'"
+        return
+    fi
+
+    local BASETRACE=$(basename $TRACE)
+    if [ "$BASETRACE" = "$TRACE" ] ; then
+        TRACE=$ANDROID_PRODUCT_OUT/traces/$TRACE
+    fi
+
+    echo "post-processing traces..."
+    rm -f $TRACE/qtrace.dexlist
+    post_trace $TRACE
+    if [ $? -ne 0 ]; then
+        echo "***"
+        echo "*** Error: malformed trace.  Did you remember to exit the emulator?"
+        echo "***"
+        return
+    fi
+    echo "generating dexlist output..."
+    /bin/ls $ANDROID_PRODUCT_OUT/system/framework/*.jar $ANDROID_PRODUCT_OUT/system/app/*.apk $ANDROID_PRODUCT_OUT/data/app/*.apk 2>/dev/null | xargs dexlist > $TRACE/qtrace.dexlist
+    echo "generating dmtrace data..."
+    q2dm -r $ANDROID_PRODUCT_OUT/symbols $TRACE $KERNEL $TRACE/dmtrace || return
+    echo "generating html file..."
+    dmtracedump -h $TRACE/dmtrace >| $TRACE/dmtrace.html || return
+    echo "done, see $TRACE/dmtrace.html for details"
+    echo "or run:"
+    echo "    traceview $TRACE/dmtrace"
+}
+
+# communicate with a running device or emulator, set up necessary state,
+# and run the hat command.
+function runhat()
+{
+    # process standard adb options
+    local adbTarget=""
+    if [ $1 = "-d" -o $1 = "-e" ]; then
+        adbTarget=$1
+        shift 1
+    elif [ $1 = "-s" ]; then
+        adbTarget="$1 $2"
+        shift 2
+    fi
+    local adbOptions=${adbTarget}
+    echo adbOptions = ${adbOptions}
+
+    # runhat options
+    local targetPid=$1
+    local outputFile=$2
+
+    if [ "$targetPid" = "" ]; then
+        echo "Usage: runhat [ -d | -e | -s serial ] target-pid [output-file]"
+        return
+    fi
+
+    # confirm hat is available
+    if [ -z $(which hat) ]; then
+        echo "hat is not available in this configuration."
+        return
+    fi
+
+    adb ${adbOptions} shell >/dev/null mkdir /data/misc
+    adb ${adbOptions} shell chmod 777 /data/misc
+
+    # send a SIGUSR1 to cause the hprof dump
+    echo "Poking $targetPid and waiting for data..."
+    adb ${adbOptions} shell kill -10 $targetPid
+    echo "Press enter when logcat shows \"hprof: heap dump completed\""
+    echo -n "> "
+    read
+
+    local availFiles=( $(adb ${adbOptions} shell ls /data/misc | grep '^heap-dump' | sed -e 's/.*heap-dump-/heap-dump-/' | sort -r | tr '[:space:][:cntrl:]' ' ') )
+    local devFile=/data/misc/${availFiles[0]}
+    local localFile=/tmp/$$-hprof
+
+    echo "Retrieving file $devFile..."
+    adb ${adbOptions} pull $devFile $localFile
+
+    adb ${adbOptions} shell rm $devFile
+
+    echo "Running hat on $localFile"
+    echo "View the output by pointing your browser at http://localhost:7000/"
+    echo ""
+    hat $localFile
+}
+
+function getbugreports()
+{
+    local reports=(`adb shell ls /sdcard/bugreports | tr -d '\r'`)
+
+    if [ ! "$reports" ]; then
+        echo "Could not locate any bugreports."
+        return
+    fi
+
+    local report
+    for report in ${reports[@]}
+    do
+        echo "/sdcard/bugreports/${report}"
+        adb pull /sdcard/bugreports/${report} ${report}
+        gunzip ${report}
+    done
+}
+
+function startviewserver()
+{
+    local port=4939
+    if [ $# -gt 0 ]; then
+            port=$1
+    fi
+    adb shell service call window 1 i32 $port
+}
+
+function stopviewserver()
+{
+    adb shell service call window 2
+}
+
+function isviewserverstarted()
+{
+    adb shell service call window 3
+}
+
+function smoketest()
+{
+    if [ ! "$ANDROID_PRODUCT_OUT" ]; then
+        echo "Couldn't locate output files.  Try running 'lunch' first." >&2
+        return
+    fi
+    T=$(gettop)
+    if [ ! "$T" ]; then
+        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
+        return
+    fi
+
+    (cd "$T" && mmm tests/SmokeTest) &&
+      adb uninstall com.android.smoketest > /dev/null &&
+      adb uninstall com.android.smoketest.tests > /dev/null &&
+      adb install $ANDROID_PRODUCT_OUT/data/app/SmokeTestApp.apk &&
+      adb install $ANDROID_PRODUCT_OUT/data/app/SmokeTest.apk &&
+      adb shell am instrument -w com.android.smoketest.tests/android.test.InstrumentationTestRunner
+}
+
+# simple shortcut to the runtest command
+function runtest()
+{
+    T=$(gettop)
+    if [ ! "$T" ]; then
+        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
+        return
+    fi
+    ("$T"/development/testrunner/runtest.py $@)
+}
+
+function godir () {
+    if [[ -z "$1" ]]; then
+        echo "Usage: godir <regex>"
+        return
+    fi
+    T=$(gettop)
+    if [[ ! -f $T/filelist ]]; then
+        echo -n "Creating index..."
+        (cd $T; find . -wholename ./out -prune -o -wholename ./.repo -prune -o -type f > filelist)
+        echo " Done"
+        echo ""
+    fi
+    local lines
+    lines=($(grep "$1" $T/filelist | sed -e 's/\/[^/]*$//' | sort | uniq)) 
+    if [[ ${#lines[@]} = 0 ]]; then
+        echo "Not found"
+        return
+    fi
+    local pathname
+    local choice
+    if [[ ${#lines[@]} > 1 ]]; then
+        while [[ -z "$pathname" ]]; do
+            local index=1
+            local line
+            for line in ${lines[@]}; do
+                printf "%6s %s\n" "[$index]" $line
+                index=$(($index + 1)) 
+            done
+            echo
+            echo -n "Select one: "
+            unset choice
+            read choice
+            if [[ $choice -gt ${#lines[@]} || $choice -lt 1 ]]; then
+                echo "Invalid choice"
+                continue
+            fi
+            pathname=${lines[$(($choice-1))]}
+        done
+    else
+        pathname=${lines[0]}
+    fi
+    cd $T/$pathname
+}
+
+# Force JAVA_HOME to point to java 1.6 if it isn't already set
+function set_java_home() {
+    if [ ! "$JAVA_HOME" ]; then
+        case `uname -s` in
+            Darwin)
+                export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home
+                ;;
+            *)
+                export JAVA_HOME=/usr/lib/jvm/java-6-sun
+                ;;
+        esac
+    fi
+}
+
+case `ps -o command -p $$` in
+    *bash*)
+        ;;
+    *)
+        echo "WARNING: Only bash is supported, use of other shell would lead to erroneous results"
+        ;;
+esac
+
+# Execute the contents of any vendorsetup.sh files we can find.
+for f in `/bin/ls vendor/*/vendorsetup.sh vendor/*/*/vendorsetup.sh device/*/*/vendorsetup.sh 2> /dev/null`
+do
+    echo "including $f"
+    . $f
+done
+unset f
diff --git a/build/libs/host/Android.mk b/build/libs/host/Android.mk
new file mode 100644 (file)
index 0000000..d02e4b2
--- /dev/null
@@ -0,0 +1,25 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+       CopyFile.c \
+       pseudolocalize.cpp
+
+ifeq ($(HOST_OS),cygwin)
+LOCAL_CFLAGS += -DWIN32_EXE
+endif
+ifeq ($(HOST_OS),darwin)
+LOCAL_CFLAGS += -DMACOSX_RSRC
+endif
+ifeq ($(HOST_OS),linux)
+endif
+
+LOCAL_MODULE:= libhost
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+
+# acp uses libhost, so we can't use
+# acp to install libhost.
+LOCAL_ACP_UNAVAILABLE:= true
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
diff --git a/build/libs/host/CopyFile.c b/build/libs/host/CopyFile.c
new file mode 100644 (file)
index 0000000..3cbe34a
--- /dev/null
@@ -0,0 +1,644 @@
+/*
+ * Copyright 2005 The Android Open Source Project
+ *
+ * Android "cp" replacement.
+ *
+ * The GNU/Linux "cp" uses O_LARGEFILE in its open() calls, utimes() instead
+ * of utime(), and getxattr()/setxattr() instead of chmod().  These are
+ * probably "better", but are non-portable, and not necessary for our
+ * purposes.
+ */
+#include <host/CopyFile.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <utime.h>
+#include <limits.h>
+#include <errno.h>
+#include <assert.h>
+
+#ifdef HAVE_MS_C_RUNTIME
+#  define  mkdir(path,mode)   _mkdir(path)
+#endif
+
+#ifndef HAVE_SYMLINKS
+#  define  lstat              stat
+#  ifndef EACCESS   /* seems to be missing from the Mingw headers */
+#    define  EACCESS            13
+#  endif
+#endif
+
+#ifndef O_BINARY
+#  define  O_BINARY  0
+#endif
+
+/*#define DEBUG_MSGS*/
+#ifdef DEBUG_MSGS
+# define DBUG(x) printf x
+#else
+# define DBUG(x) ((void)0)
+#endif
+
+#define FSSEP '/'       /* filename separator char */
+
+static int copyFileRecursive(const char* src, const char* dst, bool isCmdLine, unsigned int options);
+
+/*
+ * Returns true if the source file is newer than the destination file.
+ *
+ * The check is based on the modification date, whole seconds only.  This
+ * also returns true if the file sizes don't match.
+ */
+static bool isSourceNewer(const struct stat* pSrcStat, const struct stat* pDstStat)
+{
+    return (pSrcStat->st_mtime > pDstStat->st_mtime) ||
+           (pSrcStat->st_size != pDstStat->st_size);
+}
+
+/*
+ * Returns true if the source file has high resolution modification
+ * date.  Cygwin doesn't support st_mtim in normal build, so always
+ * return false.
+ */
+static bool isHiresMtime(const struct stat* pSrcStat)
+{
+#if defined(WIN32) || defined(USE_MINGW)
+    return 0;
+#elif defined(MACOSX_RSRC)
+    return pSrcStat->st_mtimespec.tv_nsec > 0;
+#else
+    return pSrcStat->st_mtim.tv_nsec > 0;
+#endif
+}
+
+/*
+ * Returns true if the source and destination files are actually the
+ * same thing.  We detect this by checking the inode numbers, which seems
+ * to work on Cygwin.
+ */
+static bool isSameFile(const struct stat* pSrcStat, const struct stat* pDstStat)
+{
+#ifndef HAVE_VALID_STAT_ST_INO
+    /* with MSVCRT.DLL, stat always sets st_ino to 0, and there is no simple way to */
+       /* get the equivalent information with Win32 (Cygwin does some weird stuff in   */
+       /* its winsup/cygwin/fhandler_disk_file.cc to emulate this, too complex for us) */
+       return 0;
+#else
+    return (pSrcStat->st_ino == pDstStat->st_ino);
+#endif
+}
+
+static void printCopyMsg(const char* src, const char* dst, unsigned int options)
+{
+    if ((options & COPY_VERBOSE_MASK) > 0)
+        printf("    '%s' --> '%s'\n", src, dst);
+}
+
+static void printNotNewerMsg(const char* src, const char* dst, unsigned int options)
+{
+    if ((options & COPY_VERBOSE_MASK) > 1)
+        printf("    '%s' is up-to-date\n", dst);
+}
+
+/*
+ * Copy the contents of one file to another.
+ *
+ * The files are assumed to be seeked to the start.
+ */
+static int copyFileContents(const char* dst, int dstFd, const char* src, int srcFd)
+{
+    unsigned char buf[8192];
+    ssize_t readCount, writeCount;
+
+    /*
+     * Read a chunk, write it, and repeat.
+     */
+    while (1) {
+        readCount = read(srcFd, buf, sizeof(buf));
+        if (readCount < 0) {
+            fprintf(stderr,
+                "acp: failed reading '%s': %s\n", src, strerror(errno));
+            return -1;
+        }
+
+        if (readCount > 0) {
+            writeCount = write(dstFd, buf, readCount);
+            if (writeCount < 0) {
+                fprintf(stderr,
+                    "acp: failed writing '%s': %s\n", dst, strerror(errno));
+                return -1;
+            }
+            if (writeCount != readCount) {
+                fprintf(stderr, "acp: partial write to '%s' (%d of %d)\n",
+                    dst, writeCount, readCount);
+                return -1;
+            }
+        }
+
+        if (readCount < (ssize_t) sizeof(buf))
+            break;
+    }
+
+    return 0;
+}
+
+/*
+ * Set the permissions, owner, and timestamps on the destination file
+ * equal to those of the source file.
+ *
+ * Failures here are "soft"; they don't produce warning messages and don't
+ * cause the cp command to report a failure.
+ */
+static int setPermissions(const char* dst, const struct stat* pSrcStat, unsigned int options)
+{
+    struct utimbuf ut;
+
+    if (options & COPY_TIMESTAMPS) {
+        /*
+         * Start with timestamps.  The access and mod dates are not affected
+         * by the next operations.
+         */
+        ut.actime = pSrcStat->st_atime;
+        ut.modtime = pSrcStat->st_mtime;
+        if (isHiresMtime(pSrcStat))
+            ut.modtime += 1;
+        if (utime(dst, &ut) != 0) {
+            DBUG(("---   unable to set timestamps on '%s': %s\n",
+                dst, strerror(errno)));
+        }
+    }
+
+    if (options & COPY_PERMISSIONS) {
+        /*
+         * Set the permissions.
+         */
+        if (chmod(dst, pSrcStat->st_mode & ~(S_IFMT)) != 0) {
+            DBUG(("---   unable to set perms on '%s' to 0%o: %s\n",
+                dst, pSrcStat->st_mode & ~(S_IFMT), strerror(errno)));
+        }
+#ifndef HAVE_MS_C_RUNTIME
+        /*
+         * Set the owner.
+         */
+        if (chown(dst, pSrcStat->st_uid, pSrcStat->st_gid) != 0) {
+            DBUG(("---   unable to set owner of '%s' to %d/%d: %s\n",
+                dst, pSrcStat->st_uid, pSrcStat->st_gid, strerror(errno)));
+        }
+#endif
+    }
+
+    return 0;
+}
+
+/*
+ * Copy a regular file.  If the destination file exists and is not a
+ * regular file, we fail.  However, we use stat() rather than lstat(),
+ * because it's okay to write through a symlink (the noDereference stuff
+ * only applies to the source file).
+ *
+ * If the file doesn't exist, create it.  If it does exist, truncate it.
+ */
+static int copyRegular(const char* src, const char* dst, const struct stat* pSrcStat, unsigned int options)
+{
+    struct stat dstStat;
+    int srcFd, dstFd, statResult, copyResult;
+
+    DBUG(("--- copying regular '%s' to '%s'\n", src, dst));
+
+    statResult = stat(dst, &dstStat);
+    if (statResult == 0 && !S_ISREG(dstStat.st_mode)) {
+        fprintf(stderr,
+            "acp: destination '%s' exists and is not regular file\n",
+            dst);
+        return -1;
+    } else if (statResult != 0 && errno != ENOENT) {
+        fprintf(stderr, "acp: unable to stat destination '%s'\n", dst);
+        return -1;
+    }
+
+    if (statResult == 0) {
+        if (isSameFile(pSrcStat, &dstStat)) {
+            fprintf(stderr, "acp: '%s' and '%s' are the same file\n",
+                src, dst);
+            return -1;
+        }
+        if (options & COPY_UPDATE_ONLY) {
+            if (!isSourceNewer(pSrcStat, &dstStat)) {
+                DBUG(("---  source is not newer: '%s'\n", src));
+                printNotNewerMsg(src, dst, options);
+                return 0;
+            }
+        }
+    }
+
+    /* open src */
+    srcFd = open(src, O_RDONLY | O_BINARY, 0);
+    if (srcFd < 0) {
+        fprintf(stderr, "acp: unable to open '%s': %s\n", src, strerror(errno));
+        return -1;
+    }
+
+    /* open dest with O_CREAT | O_TRUNC */
+    DBUG(("---  opening '%s'\n", dst));
+    dstFd = open(dst, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0644);
+
+    if (dstFd < 0) {
+        if (errno == ENOENT) {
+            /* this happens if the target directory doesn't exist */
+            fprintf(stderr,
+                "acp: cannot create '%s': %s\n", dst, strerror(errno));
+            (void) close(srcFd);
+            return -1;
+        }
+
+        /* if "force" is set, try removing the destination file and retry */
+        if (options & COPY_FORCE) {
+            if (unlink(dst) != 0) {
+#ifdef HAVE_MS_C_RUNTIME
+                               /* MSVCRT.DLL unlink will fail with EACCESS if the file is set read-only */
+                               /* so try to change its mode, and unlink again                           */
+                               if (errno == EACCESS) {
+                                       if (chmod(dst, S_IWRITE|S_IREAD) == 0 && unlink(dst) == 0)
+                                               goto Open_File;
+                               }
+#endif         
+                fprintf(stderr, "acp: unable to remove '%s': %s\n",
+                    dst, strerror(errno));
+                (void) close(srcFd);
+                return -1;
+            }
+#ifdef HAVE_MS_C_RUNTIME
+        Open_File:
+#endif                 
+            dstFd = open(dst, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0644);
+        }
+    }
+    if (dstFd < 0) {
+        fprintf(stderr, "acp: unable to open '%s': %s\n",
+            dst, strerror(errno));
+        (void) close(srcFd);
+        return -1;
+    }
+
+    copyResult = copyFileContents(dst, dstFd, src, srcFd);
+
+    (void) close(srcFd);
+    (void) close(dstFd);
+    if (copyResult != 0)
+        return -1;
+
+#ifdef MACOSX_RSRC
+    {
+        char* srcRsrcName = NULL;
+        char* dstRsrcName = NULL;
+        struct stat rsrcStat;
+
+        srcRsrcName = malloc(strlen(src) + 5 + 1);
+        strcpy(srcRsrcName, src);
+        strcat(srcRsrcName, "/rsrc");
+
+        dstRsrcName = malloc(strlen(dst) + 5 + 1);
+        strcpy(dstRsrcName, dst);
+        strcat(dstRsrcName, "/rsrc");
+
+        if (stat(srcRsrcName, &rsrcStat) == 0 && rsrcStat.st_size > 0) {
+            DBUG(("---  RSRC: %s --> %s\n", srcRsrcName, dstRsrcName));
+
+            srcFd = open(srcRsrcName, O_RDONLY);
+            dstFd = open(dstRsrcName, O_TRUNC | O_WRONLY, 0);
+            copyResult = -1;
+            if (srcFd >= 0 && dstFd >= 0) {
+                copyResult = copyFileContents(dstRsrcName, dstFd,
+                    srcRsrcName, srcFd);
+                (void) close(srcFd);
+                (void) close(dstFd);
+            }
+
+            if (copyResult != 0)
+                return -1;
+        }
+
+        free(srcRsrcName);
+        free(dstRsrcName);
+    }
+#endif
+
+    setPermissions(dst, pSrcStat, options);
+
+    printCopyMsg(src, dst, options);
+
+    return 0;
+}
+
+
+#ifdef HAVE_SYMLINKS
+/*
+ * Copy a symlink.  This only happens if we're in "no derefence" mode,
+ * in which we copy the links rather than the files that are pointed at.
+ *
+ * We always discard the destination file.  If it's a symlink already,
+ * we want to throw it out and replace it.  If it's not a symlink, we
+ * need to trash it so we can create one.
+ */
+static int copySymlink(const char* src, const char* dst, const struct stat* pSrcStat, unsigned int options)
+{
+    struct stat dstStat;
+    char linkBuf[PATH_MAX+1];
+    int statResult, nameLen;
+
+    assert(options & COPY_NO_DEREFERENCE);
+    DBUG(("--- copying symlink '%s' to '%s'\n", src, dst));
+
+    /* NOTE: we use lstat() here */
+    statResult = lstat(dst, &dstStat);
+    if (statResult == 0 && !S_ISREG(dstStat.st_mode)
+                         && !S_ISLNK(dstStat.st_mode)
+                                                )
+    {
+        fprintf(stderr,
+            "acp: destination '%s' exists and is not regular or symlink\n",
+            dst);
+        return -1;
+    }
+
+    if (statResult == 0) {
+        if (isSameFile(pSrcStat, &dstStat)) {
+            fprintf(stderr, "acp: '%s' and '%s' are the same file\n",
+                src, dst);
+            return -1;
+        }
+        if (options & COPY_UPDATE_ONLY) {
+            if (!isSourceNewer(pSrcStat, &dstStat)) {
+                DBUG(("---  source is not newer: '%s'\n", src));
+                printNotNewerMsg(src, dst, options);
+                return 0;
+            }
+        }
+    }
+
+    /* extract the symlink contents */
+    nameLen = readlink(src, linkBuf, sizeof(linkBuf)-1);
+    if (nameLen <= 0) {
+        fprintf(stderr, "acp: unable to read symlink '%s': %s\n",
+            src, strerror(errno));
+        return -1;
+    }
+    linkBuf[nameLen] = '\0';
+    DBUG(("--- creating symlink file '%s' (--> %s)\n", dst, linkBuf));
+
+    if (statResult == 0) {
+        DBUG(("---  removing '%s'\n", dst));
+        if (unlink(dst) != 0) {
+            fprintf(stderr, "acp: unable to remove '%s': %s\n",
+                dst, strerror(errno));
+            return -1;
+        }
+    }
+
+    if (symlink(linkBuf, dst) != 0) {
+        fprintf(stderr, "acp: unable to create symlink '%s' [%s]: %s\n",
+            dst, linkBuf, strerror(errno));
+        return -1;
+    }
+
+    /*
+     * There's no way to set the file date or access permissions, but
+     * it is possible to set the owner.
+     */
+    if (options & COPY_PERMISSIONS) {
+        if (lchown(dst, pSrcStat->st_uid, pSrcStat->st_gid) != 0)
+            DBUG(("---  lchown failed: %s\n", strerror(errno)));
+    }
+
+    printCopyMsg(src, dst, options);
+
+    return 0;
+}
+#endif /* HAVE_SYMLINKS */
+
+/*
+ * Copy the contents of one directory to another.  Both "src" and "dst"
+ * must be directories.  We will create "dst" if it does not exist.
+ */
+int copyDirectory(const char* src, const char* dst, const struct stat* pSrcStat, unsigned int options)
+{
+    int retVal = 0;
+    struct stat dstStat;
+    DIR* dir;
+    int cc, statResult;
+
+    DBUG(("--- copy dir '%s' to '%s'\n", src, dst));
+
+    statResult = stat(dst, &dstStat);
+    if (statResult == 0 && !S_ISDIR(dstStat.st_mode)) {
+        fprintf(stderr,
+            "acp: destination '%s' exists and is not a directory\n", dst);
+        return -1;
+    } else if (statResult != 0 && errno != ENOENT) {
+        fprintf(stderr, "acp: unable to stat destination '%s'\n", dst);
+        return -1;
+    }
+
+    if (statResult == 0) {
+        if (isSameFile(pSrcStat, &dstStat)) {
+            fprintf(stderr,
+                "acp: cannot copy directory into itself ('%s' and '%s')\n",
+                src, dst);
+            return -1;
+        }
+    } else {
+        DBUG(("---  creating dir '%s'\n", dst));
+        cc = mkdir(dst, 0755);
+        if (cc != 0) {
+            fprintf(stderr, "acp: unable to create directory '%s': %s\n",
+                dst, strerror(errno));
+            return -1;
+        }
+
+        /* only print on mkdir */
+        printCopyMsg(src, dst, options);
+    }
+
+    /*
+     * Open the directory, and plow through its contents.
+     */
+    dir = opendir(src);
+    if (dir == NULL) {
+        fprintf(stderr, "acp: unable to open directory '%s': %s\n",
+            src, strerror(errno));
+        return -1;
+    }
+
+    while (1) {
+        struct dirent* ent;
+        char* srcFile;
+        char* dstFile;
+        int srcLen, dstLen, nameLen;
+
+        ent = readdir(dir);
+        if (ent == NULL)
+            break;
+
+        if (strcmp(ent->d_name, ".") == 0 ||
+            strcmp(ent->d_name, "..") == 0)
+        {
+            continue;
+        }
+
+        nameLen = strlen(ent->d_name);
+        srcLen = strlen(src);
+        dstLen = strlen(dst);
+
+        srcFile = malloc(srcLen +1 + nameLen +1);
+        memcpy(srcFile, src, srcLen);
+        srcFile[srcLen] = FSSEP;
+        memcpy(srcFile + srcLen+1, ent->d_name, nameLen +1);
+
+        dstFile = malloc(dstLen +1 + nameLen +1);
+        memcpy(dstFile, dst, dstLen);
+        dstFile[dstLen] = FSSEP;
+        memcpy(dstFile + dstLen+1, ent->d_name, nameLen +1);
+
+        if (copyFileRecursive(srcFile, dstFile, false, options) != 0)
+            retVal = -1;        /* note failure and keep going */
+
+        free(srcFile);
+        free(dstFile);
+    }
+    closedir(dir);
+
+    setPermissions(dst, pSrcStat, options);
+
+    return retVal;
+}
+
+/*
+ * Do the actual copy.  This is called recursively from copyDirectory().
+ *
+ * "dst" should only be a directory if "src" is also a directory.
+ *
+ * Returns 0 on success.
+ */
+static int copyFileRecursive(const char* src, const char* dst, bool isCmdLine, unsigned int options)
+{
+    char* srcExe = NULL;
+    char* dstExe = NULL;
+    char* dstDir = NULL;
+    struct stat srcStat;
+    int retVal = 0;
+    int statResult, statErrno;
+
+    /*
+     * Stat the source file.  If it doesn't exist, fail.
+     */
+    if (options & COPY_NO_DEREFERENCE)
+        statResult = lstat(src, &srcStat);
+    else
+        statResult = stat(src, &srcStat);
+    statErrno = errno;        /* preserve across .exe attempt */
+
+#ifdef WIN32_EXE
+    /*
+     * Here's the interesting part.  Under Cygwin, if you have a file
+     * called "foo.exe", stat("foo", ...) will succeed, but open("foo", ...)
+     * will fail.  We need to figure out what its name is supposed to be
+     * so we can create the correct destination file.
+     *
+     * If we don't have the "-e" flag set, we want "acp foo bar" to fail,
+     * not automatically find "foo.exe".  That way, if we really were
+     * trying to copy "foo", it doesn't grab something we don't want.
+     */
+    if (isCmdLine && statResult == 0) {
+        int tmpFd;
+        tmpFd = open(src, O_RDONLY | O_BINARY, 0);
+        if (tmpFd < 0) {
+            statResult = -1;
+            statErrno = ENOENT;
+        } else {
+            (void) close(tmpFd);
+        }
+    }
+
+    /*
+     * If we didn't find the file, try it again with ".exe".
+     */
+    if (isCmdLine && statResult < 0 && statErrno == ENOENT && (options & COPY_TRY_EXE)) {
+        srcExe = malloc(strlen(src) + 4 +1);
+        strcpy(srcExe, src);
+        strcat(srcExe, ".exe");
+
+        if (options & COPY_NO_DEREFERENCE)
+            statResult = lstat(srcExe, &srcStat);
+        else
+            statResult = stat(srcExe, &srcStat);
+
+        if (statResult == 0 && !S_ISREG(srcStat.st_mode))
+            statResult = -1;        /* fail, use original statErrno below */
+
+        if (statResult == 0) {
+            /* found a .exe, copy that instead */
+            dstExe = malloc(strlen(dst) + 4 +1);
+            strcpy(dstExe, dst);
+            strcat(dstExe, ".exe");
+
+            src = srcExe;
+            dst = dstExe;
+        } else {
+            DBUG(("---  couldn't find '%s' either\n", srcExe));
+        }
+    }
+#endif
+    if (statResult < 0) {
+        if (statErrno == ENOENT)
+            fprintf(stderr, "acp: file '%s' does not exist\n", src);
+        else
+            fprintf(stderr, "acp: unable to stat '%s': %s\n",
+                src, strerror(statErrno));
+        retVal = -1;
+        goto bail;
+    }
+
+    /*
+     * If "src" is a directory, ignore it if "recursive" isn't set.
+     *
+     * We want to create "dst" as a directory (or verify that it already
+     * exists as a directory), and then copy its contents.
+     */
+    if (S_ISDIR(srcStat.st_mode)) {
+        if (!(options & COPY_RECURSIVE)) {
+            fprintf(stderr, "acp: omitting directory '%s'\n", src);
+        } else {
+            retVal = copyDirectory(src, dst, &srcStat, options);
+        }
+#ifdef HAVE_SYMLINKS
+    } else if (S_ISLNK(srcStat.st_mode)) {
+        retVal = copySymlink(src, dst, &srcStat, options);
+#endif         
+    } else if (S_ISREG(srcStat.st_mode)) {
+        retVal = copyRegular(src, dst, &srcStat, options);
+    } else {
+        fprintf(stderr, "acp: skipping unusual file '%s' (mode=0%o)\n",
+            src, srcStat.st_mode);
+        retVal = -1;
+    }
+
+bail:
+    free(srcExe);
+    free(dstExe);
+    free(dstDir);
+    return retVal;
+}
+
+int copyFile(const char* src, const char* dst, unsigned int options)
+{
+    return copyFileRecursive(src, dst, true, options);
+}
+
+
diff --git a/build/libs/host/include/host/CopyFile.h b/build/libs/host/include/host/CopyFile.h
new file mode 100644 (file)
index 0000000..e65712b
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _HOST_COPYFILE_H
+#define _HOST_COPYFILE_H
+
+#include <stdbool.h>
+#include <sys/stat.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// command line options
+enum {
+    COPY_NO_DEREFERENCE = 0x00010000, // copy symlink link instead of target
+    COPY_TRY_EXE        = 0x00020000, // on Win32, try adding '.exe' to filename
+    COPY_FORCE          = 0x00040000, // override access permissions
+    COPY_PERMISSIONS    = 0x00080000, // preserve mode, ownership, timestamps
+    COPY_TIMESTAMPS     = 0x00100000, // preserve mode, ownership, timestamps
+    COPY_RECURSIVE      = 0x00200000, // copy directories
+    COPY_UPDATE_ONLY    = 0x00400000, // only copy if source file is newer
+    COPY_VERBOSE_MASK   = 0x000000ff  // talk lots
+};
+
+int copyFile(const char* src, const char* dst, unsigned int options);
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif // _HOST_COPYFILE_H
+
diff --git a/build/libs/host/include/host/Directories.h b/build/libs/host/include/host/Directories.h
new file mode 100644 (file)
index 0000000..fccce46
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef HOST_MKDIRS_H
+#define HOST_MKDIRS_H
+
+#include <string>
+
+std::string parent_dir(const std::string& path);
+
+extern "C" int mkdirs(const char* path);
+
+#endif // HOST_MKDIRS_H
diff --git a/build/libs/host/include/host/pseudolocalize.h b/build/libs/host/include/host/pseudolocalize.h
new file mode 100644 (file)
index 0000000..94cb034
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef HOST_PSEUDOLOCALIZE_H
+#define HOST_PSEUDOLOCALIZE_H
+
+#include <string>
+
+std::string pseudolocalize_string(const std::string& source);
+
+#endif // HOST_PSEUDOLOCALIZE_H
+
diff --git a/build/libs/host/list.java b/build/libs/host/list.java
new file mode 100644 (file)
index 0000000..30546e3
--- /dev/null
@@ -0,0 +1,35 @@
+import java.io.*;
+
+public class list {
+    private static char nibble(int c) {
+        return (char)(c < 10 ? ('0' + c) : ('a' + (c-10)));
+    }
+    public static void main(String[] argv)
+    {
+        ByteArrayOutputStream stream = new ByteArrayOutputStream(100);
+        OutputStreamWriter writer = null;
+        try {
+            writer = new OutputStreamWriter(stream, "utf-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace(System.err);
+        }
+
+        int n = Integer.parseInt(argv[1], 16);
+        try {
+            writer.write(n);
+            writer.close();
+        } catch (IOException e) {
+            e.printStackTrace(System.err);
+        }
+
+        byte[] array = stream.toByteArray();
+
+        System.out.print("        case '" + argv[0] + "':   return \"");
+        for (int i=0; i<array.length; i++) {
+            int b = array[i];
+            System.out.print("\\x" + nibble((b >> 4) & 0x0f) + nibble(b & 0xf));
+        }
+        System.out.println("\";");
+    }
+}
+
diff --git a/build/libs/host/pseudolocalize.cpp b/build/libs/host/pseudolocalize.cpp
new file mode 100644 (file)
index 0000000..a2b3c2f
--- /dev/null
@@ -0,0 +1,119 @@
+#include <host/pseudolocalize.h>
+
+using namespace std;
+
+static const char*
+pseudolocalize_char(char c)
+{
+    switch (c) {
+        case 'a':   return "\xc4\x83";
+        case 'b':   return "\xcf\x84";
+        case 'c':   return "\xc4\x8b";
+        case 'd':   return "\xc4\x8f";
+        case 'e':   return "\xc4\x99";
+        case 'f':   return "\xc6\x92";
+        case 'g':   return "\xc4\x9d";
+        case 'h':   return "\xd1\x9b";
+        case 'i':   return "\xcf\x8a";
+        case 'j':   return "\xc4\xb5";
+        case 'k':   return "\xc4\xb8";
+        case 'l':   return "\xc4\xba";
+        case 'm':   return "\xe1\xb8\xbf";
+        case 'n':   return "\xd0\xb8";
+        case 'o':   return "\xcf\x8c";
+        case 'p':   return "\xcf\x81";
+        case 'q':   return "\x51";
+        case 'r':   return "\xd2\x91";
+        case 's':   return "\xc5\xa1";
+        case 't':   return "\xd1\x82";
+        case 'u':   return "\xce\xb0";
+        case 'v':   return "\x56";
+        case 'w':   return "\xe1\xba\x85";
+        case 'x':   return "\xd1\x85";
+        case 'y':   return "\xe1\xbb\xb3";
+        case 'z':   return "\xc5\xba";
+        case 'A':   return "\xc3\x85";
+        case 'B':   return "\xce\xb2";
+        case 'C':   return "\xc4\x88";
+        case 'D':   return "\xc4\x90";
+        case 'E':   return "\xd0\x84";
+        case 'F':   return "\xce\x93";
+        case 'G':   return "\xc4\x9e";
+        case 'H':   return "\xc4\xa6";
+        case 'I':   return "\xd0\x87";
+        case 'J':   return "\xc4\xb5";
+        case 'K':   return "\xc4\xb6";
+        case 'L':   return "\xc5\x81";
+        case 'M':   return "\xe1\xb8\xbe";
+        case 'N':   return "\xc5\x83";
+        case 'O':   return "\xce\x98";
+        case 'P':   return "\xcf\x81";
+        case 'Q':   return "\x71";
+        case 'R':   return "\xd0\xaf";
+        case 'S':   return "\xc8\x98";
+        case 'T':   return "\xc5\xa6";
+        case 'U':   return "\xc5\xa8";
+        case 'V':   return "\xce\xbd";
+        case 'W':   return "\xe1\xba\x84";
+        case 'X':   return "\xc3\x97";
+        case 'Y':   return "\xc2\xa5";
+        case 'Z':   return "\xc5\xbd";
+        default:    return NULL;
+    }
+}
+
+/**
+ * Converts characters so they look like they've been localized.
+ *
+ * Note: This leaves escape sequences untouched so they can later be
+ * processed by ResTable::collectString in the normal way.
+ */
+string
+pseudolocalize_string(const string& source)
+{
+    const char* s = source.c_str();
+    string result;
+    const size_t I = source.length();
+    for (size_t i=0; i<I; i++) {
+        char c = s[i];
+        if (c == '\\') {
+            if (i<I-1) {
+                result += '\\';
+                i++;
+                c = s[i];
+                switch (c) {
+                    case 'u':
+                        // this one takes up 5 chars
+                        result += string(s+i, 5);
+                        i += 4;
+                        break;
+                    case 't':
+                    case 'n':
+                    case '#':
+                    case '@':
+                    case '?':
+                    case '"':
+                    case '\'':
+                    case '\\':
+                    default:
+                        result += c;
+                        break;
+                }
+            } else {
+                result += c;
+            }
+        } else {
+            const char* p = pseudolocalize_char(c);
+            if (p != NULL) {
+                result += p;
+            } else {
+                result += c;
+            }
+        }
+    }
+
+    //printf("result=\'%s\'\n", result.c_str());
+    return result;
+}
+
+
diff --git a/build/target/board/Android.mk b/build/target/board/Android.mk
new file mode 100644 (file)
index 0000000..82dee3c
--- /dev/null
@@ -0,0 +1,43 @@
+#
+# Set up product-global definitions and include product-specific rules.
+#
+
+ifneq ($(strip $(TARGET_NO_BOOTLOADER)),true)
+  INSTALLED_BOOTLOADER_MODULE := $(PRODUCT_OUT)/bootloader
+  ifeq ($(strip $(TARGET_BOOTLOADER_IS_2ND)),true)
+    INSTALLED_2NDBOOTLOADER_TARGET := $(PRODUCT_OUT)/2ndbootloader
+  else
+    INSTALLED_2NDBOOTLOADER_TARGET :=
+  endif
+else
+  INSTALLED_BOOTLOADER_MODULE :=
+  INSTALLED_2NDBOOTLOADER_TARGET :=
+endif  # TARGET_NO_BOOTLOADER
+
+ifneq ($(strip $(TARGET_NO_KERNEL)),true)
+  INSTALLED_KERNEL_TARGET := $(PRODUCT_OUT)/kernel
+else
+  INSTALLED_KERNEL_TARGET :=
+endif
+
+# Use the add-radio-file function to add values to this variable.
+INSTALLED_RADIOIMAGE_TARGET :=
+
+-include $(TARGET_DEVICE_DIR)/AndroidBoard.mk
+
+# Generate a file that contains various information about the
+# device we're building for.  This file is typically packaged up
+# with everything else.
+#
+# If the file "board-info.txt" appears in $(TARGET_DEVICE_DIR),
+# it will be appended to the output file.
+#
+INSTALLED_ANDROID_INFO_TXT_TARGET := $(PRODUCT_OUT)/android-info.txt
+board_info_txt := $(wildcard $(TARGET_DEVICE_DIR)/board-info.txt)
+$(INSTALLED_ANDROID_INFO_TXT_TARGET): $(board_info_txt)
+       $(call pretty,"Generated: ($@)")
+ifdef board_info_txt
+       $(hide) cat $< > $@
+else
+       $(hide) echo "board=$(TARGET_BOOTLOADER_BOARD_NAME)" > $@
+endif
diff --git a/build/target/board/emulator/AndroidBoard.mk b/build/target/board/emulator/AndroidBoard.mk
new file mode 100644 (file)
index 0000000..09badee
--- /dev/null
@@ -0,0 +1,10 @@
+LOCAL_PATH := $(call my-dir)
+
+file := $(TARGET_OUT_KEYLAYOUT)/tuttle2.kl
+ALL_PREBUILT += $(file)
+$(file) : $(LOCAL_PATH)/tuttle2.kl | $(ACP)
+       $(transform-prebuilt-to-target)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := tuttle2.kcm
+include $(BUILD_KEY_CHAR_MAP)
diff --git a/build/target/board/emulator/BoardConfig.mk b/build/target/board/emulator/BoardConfig.mk
new file mode 100644 (file)
index 0000000..9ab607a
--- /dev/null
@@ -0,0 +1,12 @@
+# config.mk
+# 
+# Product-specific compile-time definitions.
+#
+
+# The generic product target doesn't have any hardware-specific pieces.
+TARGET_NO_BOOTLOADER := true
+TARGET_NO_KERNEL := true
+HAVE_HTC_AUDIO_DRIVER := true
+
+# no hardware camera
+USE_CAMERA_STUB := true
diff --git a/build/target/board/emulator/README.txt b/build/target/board/emulator/README.txt
new file mode 100644 (file)
index 0000000..6a1ec89
--- /dev/null
@@ -0,0 +1,10 @@
+The "emulator" product defines an almost non-hardware-specific target
+without a kernel or bootloader, except that it defines the
+HAVE_HTC_AUDIO_DRIVER constant, since that is what the emulator
+emulates currently.
+
+It can be used to build the entire user-level system, and
+will work with the emulator.
+
+It is not a product "base class"; no other products inherit
+from it or use it in any way.
diff --git a/build/target/board/emulator/tuttle2.kcm b/build/target/board/emulator/tuttle2.kcm
new file mode 100644 (file)
index 0000000..0a2dd8c
--- /dev/null
@@ -0,0 +1,66 @@
+[type=QWERTY]                                           
+                                                        
+# keycode       display number  base    caps    fn      caps_fn
+                                                        
+A               'A'     '%'     'a'     'A'     '%'     0x00
+B               'B'     '='     'b'     'B'     '='     0x00
+C               'C'     '8'     'c'     'C'     '8'     0x00E7
+D               'D'     '5'     'd'     'D'     '5'     0x00
+E               'E'     '2'     'e'     'E'     '2'     0x0301
+F               'F'     '6'     'f'     'F'     '6'     0x00A5
+G               'G'     '-'     'g'     'G'     '-'     '_'
+H               'H'     '['     'h'     'H'     '['     '{'
+I               'I'     '$'     'i'     'I'     '$'     0x0302
+J               'J'     ']'     'j'     'J'     ']'     '}'
+K               'K'     '"'     'k'     'K'     '"'     '~'
+L               'L'     '''     'l'     'L'     '''     '`'
+M               'M'     '>'     'm'     'M'     '>'     0x00
+N               'N'     '<'     'n'     'N'     '<'     0x0303
+O               'O'     '('     'o'     'O'     '('     0x00
+P               'P'     ')'     'p'     'P'     ')'     0x00
+Q               'Q'     '*'     'q'     'Q'     '*'     0x0300
+R               'R'     '3'     'r'     'R'     '3'     0x20AC
+S               'S'     '4'     's'     'S'     '4'     0x00DF
+T               'T'     '+'     't'     'T'     '+'     0x00A3
+U               'U'     '&'     'u'     'U'     '&'     0x0308
+V               'V'     '9'     'v'     'V'     '9'     '^'
+W               'W'     '1'     'w'     'W'     '1'     0x00
+X               'X'     '7'     'x'     'X'     '7'     0xEF00
+Y               'Y'     '!'     'y'     'Y'     '!'     0x00A1
+Z               'Z'     '#'     'z'     'Z'     '#'     0x00
+                                                        
+COMMA           ','     ','     ','     ';'     ';'     '|'
+PERIOD          '.'     '.'     '.'     ':'     ':'     0x2026
+AT              '@'     '0'     '@'     '0'     '0'     0x2022
+SLASH           '/'     '/'     '/'     '?'     '?'     '\'
+                                                        
+SPACE           0x20    0x20    0x20    0x20    0xEF01  0xEF01
+ENTER         0xa     0xa     0xa     0xa     0xa     0xa
+                                                        
+# on pc keyboards
+TAB             0x9     0x9     0x9     0x9     0x9     0x9
+0               '0'     '0'     '0'     ')'     ')'     ')'
+1               '1'     '1'     '1'     '!'     '!'     '!'
+2               '2'     '2'     '2'     '@'     '@'     '@'
+3               '3'     '3'     '3'     '#'     '#'     '#'
+4               '4'     '4'     '4'     '$'     '$'     '$'
+5               '5'     '5'     '5'     '%'     '%'     '%'
+6               '6'     '6'     '6'     '^'     '^'     '^'
+7               '7'     '7'     '7'     '&'     '&'     '&'
+8               '8'     '8'     '8'     '*'     '*'     '*'
+9               '9'     '9'     '9'     '('     '('     '('
+                                                        
+GRAVE           '`'     '`'     '`'     '~'     '`'     '~'
+MINUS           '-'     '-'     '-'     '_'     '-'     '_'
+EQUALS          '='     '='     '='     '+'     '='     '+'
+LEFT_BRACKET    '['     '['     '['     '{'     '['     '{'
+RIGHT_BRACKET   ']'     ']'     ']'     '}'     ']'     '}'
+BACKSLASH       '\'     '\'     '\'     '|'     '\'     '|'
+SEMICOLON       ';'     ';'     ';'     ':'     ';'     ':'
+APOSTROPHE      '''     '''     '''     '"'     '''     '"'
+STAR            '*'     '*'     '*'     '*'     '*'     '*'
+POUND           '#'     '#'     '#'     '#'     '#'     '#'
+PLUS            '+'     '+'     '+'     '+'     '+'     '+'
+                                                        
+                                                        
+                                                        
diff --git a/build/target/board/emulator/tuttle2.kl b/build/target/board/emulator/tuttle2.kl
new file mode 100644 (file)
index 0000000..a48a5ab
--- /dev/null
@@ -0,0 +1,74 @@
+key 2     1
+key 3     2
+key 4     3
+key 5     4
+key 6     5
+key 7     6
+key 8     7
+key 9     8
+key 10    9
+key 11    0
+key 158   BACK              WAKE_DROPPED
+key 230   SOFT_RIGHT        WAKE
+key 60    SOFT_RIGHT        WAKE
+key 107   ENDCALL           WAKE_DROPPED
+key 62    ENDCALL           WAKE_DROPPED
+key 229   MENU         WAKE_DROPPED
+key 59    MENU         WAKE_DROPPED
+key 228   POUND
+key 227   STAR
+key 231   CALL              WAKE_DROPPED
+key 61    CALL              WAKE_DROPPED
+key 232   DPAD_CENTER       WAKE_DROPPED
+key 108   DPAD_DOWN         WAKE_DROPPED
+key 103   DPAD_UP           WAKE_DROPPED
+key 102   HOME              WAKE
+key 105   DPAD_LEFT         WAKE_DROPPED
+key 106   DPAD_RIGHT        WAKE_DROPPED
+key 115   VOLUME_UP
+key 114   VOLUME_DOWN
+key 116   POWER             WAKE
+key 212   SLASH
+
+key 16    Q
+key 17    W
+key 18    E
+key 19    R
+key 20    T
+key 21    Y
+key 22    U
+key 23    I
+key 24    O
+key 25    P
+
+key 30    A
+key 31    S
+key 32    D
+key 33    F
+key 34    G
+key 35    H
+key 36    J
+key 37    K
+key 38    L
+key 14    DEL
+        
+key 44    Z
+key 45    X
+key 46    C
+key 47    V
+key 48    B
+key 49    N
+key 50    M
+key 51    COMMA
+key 52    PERIOD
+key 28    ENTER
+        
+key 56    ALT_LEFT
+key 42    SHIFT_LEFT
+key 215   AT
+key 57    SPACE
+key 53    SLASH
+key 127   SYM
+key 100   ALT_RIGHT
+
+key 399   GRAVE
diff --git a/build/target/board/generic/AndroidBoard.mk b/build/target/board/generic/AndroidBoard.mk
new file mode 100644 (file)
index 0000000..09badee
--- /dev/null
@@ -0,0 +1,10 @@
+LOCAL_PATH := $(call my-dir)
+
+file := $(TARGET_OUT_KEYLAYOUT)/tuttle2.kl
+ALL_PREBUILT += $(file)
+$(file) : $(LOCAL_PATH)/tuttle2.kl | $(ACP)
+       $(transform-prebuilt-to-target)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := tuttle2.kcm
+include $(BUILD_KEY_CHAR_MAP)
diff --git a/build/target/board/generic/BoardConfig.mk b/build/target/board/generic/BoardConfig.mk
new file mode 100644 (file)
index 0000000..26bf6ab
--- /dev/null
@@ -0,0 +1,17 @@
+# config.mk
+#
+# Product-specific compile-time definitions.
+#
+
+# The generic product target doesn't have any hardware-specific pieces.
+TARGET_NO_BOOTLOADER := true
+TARGET_NO_KERNEL := true
+TARGET_CPU_ABI := armeabi
+HAVE_HTC_AUDIO_DRIVER := true
+BOARD_USES_GENERIC_AUDIO := true
+
+# no hardware camera
+USE_CAMERA_STUB := true
+
+# Set /system/bin/sh to mksh, not ash, to test the transition.
+TARGET_SHELL := mksh
diff --git a/build/target/board/generic/README.txt b/build/target/board/generic/README.txt
new file mode 100644 (file)
index 0000000..ddac68e
--- /dev/null
@@ -0,0 +1,9 @@
+The "generic" product defines a non-hardware-specific target
+without a kernel or bootloader.
+
+It can be used to build the entire user-level system, and
+will work with the emulator, though sound will not work
+(see the "emulator" product for that).
+
+It is not a product "base class"; no other products inherit
+from it or use it in any way.
diff --git a/build/target/board/generic/device.mk b/build/target/board/generic/device.mk
new file mode 100644 (file)
index 0000000..0b4dc27
--- /dev/null
@@ -0,0 +1,26 @@
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This is a build configuration for the product aspects that
+# are specific to the emulator.
+
+PRODUCT_PROPERTY_OVERRIDES := \
+    ro.ril.hsxpa=1 \
+    ro.ril.gprsclass=10
+
+PRODUCT_COPY_FILES := \
+    development/data/etc/apns-conf.xml:system/etc/apns-conf.xml \
+    development/data/etc/vold.conf:system/etc/vold.conf
diff --git a/build/target/board/generic/system.prop b/build/target/board/generic/system.prop
new file mode 100644 (file)
index 0000000..f2424c9
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# system.prop for generic sdk 
+#
+
+rild.libpath=/system/lib/libreference-ril.so
+rild.libargs=-d /dev/ttyS0
diff --git a/build/target/board/generic/tuttle2.kcm b/build/target/board/generic/tuttle2.kcm
new file mode 100644 (file)
index 0000000..0a2dd8c
--- /dev/null
@@ -0,0 +1,66 @@
+[type=QWERTY]                                           
+                                                        
+# keycode       display number  base    caps    fn      caps_fn
+                                                        
+A               'A'     '%'     'a'     'A'     '%'     0x00
+B               'B'     '='     'b'     'B'     '='     0x00
+C               'C'     '8'     'c'     'C'     '8'     0x00E7
+D               'D'     '5'     'd'     'D'     '5'     0x00
+E               'E'     '2'     'e'     'E'     '2'     0x0301
+F               'F'     '6'     'f'     'F'     '6'     0x00A5
+G               'G'     '-'     'g'     'G'     '-'     '_'
+H               'H'     '['     'h'     'H'     '['     '{'
+I               'I'     '$'     'i'     'I'     '$'     0x0302
+J               'J'     ']'     'j'     'J'     ']'     '}'
+K               'K'     '"'     'k'     'K'     '"'     '~'
+L               'L'     '''     'l'     'L'     '''     '`'
+M               'M'     '>'     'm'     'M'     '>'     0x00
+N               'N'     '<'     'n'     'N'     '<'     0x0303
+O               'O'     '('     'o'     'O'     '('     0x00
+P               'P'     ')'     'p'     'P'     ')'     0x00
+Q               'Q'     '*'     'q'     'Q'     '*'     0x0300
+R               'R'     '3'     'r'     'R'     '3'     0x20AC
+S               'S'     '4'     's'     'S'     '4'     0x00DF
+T               'T'     '+'     't'     'T'     '+'     0x00A3
+U               'U'     '&'     'u'     'U'     '&'     0x0308
+V               'V'     '9'     'v'     'V'     '9'     '^'
+W               'W'     '1'     'w'     'W'     '1'     0x00
+X               'X'     '7'     'x'     'X'     '7'     0xEF00
+Y               'Y'     '!'     'y'     'Y'     '!'     0x00A1
+Z               'Z'     '#'     'z'     'Z'     '#'     0x00
+                                                        
+COMMA           ','     ','     ','     ';'     ';'     '|'
+PERIOD          '.'     '.'     '.'     ':'     ':'     0x2026
+AT              '@'     '0'     '@'     '0'     '0'     0x2022
+SLASH           '/'     '/'     '/'     '?'     '?'     '\'
+                                                        
+SPACE           0x20    0x20    0x20    0x20    0xEF01  0xEF01
+ENTER         0xa     0xa     0xa     0xa     0xa     0xa
+                                                        
+# on pc keyboards
+TAB             0x9     0x9     0x9     0x9     0x9     0x9
+0               '0'     '0'     '0'     ')'     ')'     ')'
+1               '1'     '1'     '1'     '!'     '!'     '!'
+2               '2'     '2'     '2'     '@'     '@'     '@'
+3               '3'     '3'     '3'     '#'     '#'     '#'
+4               '4'     '4'     '4'     '$'     '$'     '$'
+5               '5'     '5'     '5'     '%'     '%'     '%'
+6               '6'     '6'     '6'     '^'     '^'     '^'
+7               '7'     '7'     '7'     '&'     '&'     '&'
+8               '8'     '8'     '8'     '*'     '*'     '*'
+9               '9'     '9'     '9'     '('     '('     '('
+                                                        
+GRAVE           '`'     '`'     '`'     '~'     '`'     '~'
+MINUS           '-'     '-'     '-'     '_'     '-'     '_'
+EQUALS          '='     '='     '='     '+'     '='     '+'
+LEFT_BRACKET    '['     '['     '['     '{'     '['     '{'
+RIGHT_BRACKET   ']'     ']'     ']'     '}'     ']'     '}'
+BACKSLASH       '\'     '\'     '\'     '|'     '\'     '|'
+SEMICOLON       ';'     ';'     ';'     ':'     ';'     ':'
+APOSTROPHE      '''     '''     '''     '"'     '''     '"'
+STAR            '*'     '*'     '*'     '*'     '*'     '*'
+POUND           '#'     '#'     '#'     '#'     '#'     '#'
+PLUS            '+'     '+'     '+'     '+'     '+'     '+'
+                                                        
+                                                        
+                                                        
diff --git a/build/target/board/generic/tuttle2.kl b/build/target/board/generic/tuttle2.kl
new file mode 100644 (file)
index 0000000..a78a6eb
--- /dev/null
@@ -0,0 +1,74 @@
+key 2     1
+key 3     2
+key 4     3
+key 5     4
+key 6     5
+key 7     6
+key 8     7
+key 9     8
+key 10    9
+key 11    0
+key 158   BACK              WAKE_DROPPED
+key 230   SOFT_RIGHT        WAKE
+key 60    SOFT_RIGHT        WAKE
+key 107   ENDCALL           WAKE_DROPPED
+key 62    ENDCALL           WAKE_DROPPED
+key 229   MENU         WAKE_DROPPED
+key 59    MENU         WAKE_DROPPED
+key 228   POUND
+key 227   STAR
+key 231   CALL              WAKE_DROPPED
+key 61    CALL              WAKE_DROPPED
+key 232   DPAD_CENTER       WAKE_DROPPED
+key 108   DPAD_DOWN         WAKE_DROPPED
+key 103   DPAD_UP           WAKE_DROPPED
+key 102   HOME              WAKE
+key 105   DPAD_LEFT         WAKE_DROPPED
+key 106   DPAD_RIGHT        WAKE_DROPPED
+key 115   VOLUME_UP
+key 114   VOLUME_DOWN
+key 116   POWER             WAKE
+key 212   SLASH
+
+key 16    Q
+key 17    W
+key 18    E
+key 19    R
+key 20    T
+key 21    Y
+key 22    U
+key 23    I
+key 24    O
+key 25    P
+
+key 30    A
+key 31    S
+key 32    D
+key 33    F
+key 34    G
+key 35    H
+key 36    J
+key 37    K
+key 38    L
+key 14    DEL
+        
+key 44    Z
+key 45    X
+key 46    C
+key 47    V
+key 48    B
+key 49    N
+key 50    M
+key 51    COMMA
+key 52    PERIOD
+key 28    ENTER
+        
+key 56    ALT_LEFT
+key 42    SHIFT_LEFT
+key 215   AT
+key 57    SPACE
+key 53    SLASH
+key 127   SYM
+key 100   ALT_LEFT
+
+key 399   GRAVE
diff --git a/build/target/board/generic_x86/AndroidBoard.mk b/build/target/board/generic_x86/AndroidBoard.mk
new file mode 100644 (file)
index 0000000..01ca1b7
--- /dev/null
@@ -0,0 +1,11 @@
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(TARGET_PREBUILT_KERNEL),)
+LOCAL_KERNEL := prebuilt/android-x86/kernel/kernel
+else
+LOCAL_KERNEL := $(TARGET_PREBUILT_KERNEL)
+endif
+
+PRODUCT_COPY_FILES += \
+    $(LOCAL_KERNEL):kernel \
+    $(LOCAL_PATH)/init.rc:root/init.rc
diff --git a/build/target/board/generic_x86/BoardConfig.mk b/build/target/board/generic_x86/BoardConfig.mk
new file mode 100644 (file)
index 0000000..2268d41
--- /dev/null
@@ -0,0 +1,30 @@
+TARGET_ARCH=x86
+DISABLE_DEXPREOPT := true
+TARGET_COMPRESS_MODULE_SYMBOLS := false
+TARGET_PRELINK_MODULE := false
+TARGET_NO_RECOVERY := true
+TARGET_HARDWARE_3D := false
+BOARD_USES_GENERIC_AUDIO := true
+USE_CAMERA_STUB := true
+TARGET_PROVIDES_INIT_RC := true
+USE_CUSTOM_RUNTIME_HEAP_MAX := "32M"
+TARGET_CPU_ABI := x86
+TARGET_USERIMAGES_USE_EXT4 := true
+TARGET_BOOTIMAGE_USE_EXT2 := true
+
+# For VirtualBox and likely other emulators
+BOARD_INSTALLER_CMDLINE := init=/init console=ttyS0 console=tty0 androidboot.hardware=generic_x86 vga=788 androidboot.console=tty0 verbose
+BOARD_KERNEL_CMDLINE := init=/init console=tty0 console=ttyS0 androidboot.hardware=generic_x86 vga=788 androidboot.console=tty0 verbose
+TARGET_USE_DISKINSTALLER := true
+TARGET_DISK_LAYOUT_CONFIG := build/target/board/generic_x86/disk_layout.conf
+BOARD_BOOTIMAGE_MAX_SIZE := 8388608
+BOARD_SYSLOADER_MAX_SIZE := 7340032
+BOARD_FLASH_BLOCK_SIZE := 512
+BOARD_USERDATAIMAGE_PARTITION_SIZE := 50M
+BOARD_INSTALLERIMAGE_PARTITION_SIZE := 500M
+TARGET_USERIMAGES_SPARSE_EXT_DISABLED := true
+
+
+# The eth0 device should be started with dhcp on boot.
+# Useful for emulators that don't provide a wifi connection.
+NET_ETH0_STARTONBOOT := true
diff --git a/build/target/board/generic_x86/README.txt b/build/target/board/generic_x86/README.txt
new file mode 100644 (file)
index 0000000..585a373
--- /dev/null
@@ -0,0 +1,29 @@
+The generic_x86 board target provides basic services on very basic
+hardware (really for an emulation). To build with generic_x86, you will
+need an appropriate kernel for your emulation (or device).
+
+A1. Create a new top level directory and pull the AOSP repository
+        mkdir $HOME/AOSP
+        cd $HOME/AOSP
+        repo init -u git://android.git.kernel.org/platform/manifest.git
+        repo sync
+
+A2. Copy in the kernel
+        cd $HOME/AOSP
+        cp ~/bzImage.your_device $HOME/AOSP/prebuilt/android-x86/kernel/kernel
+
+A3. Build
+        cd $HOME/AOSP
+        source build/envsetup.sh
+        lunch generic_x86-eng
+        make -j8
+
+The build will generate some image files whose format may or may not be correct for your
+device. You can build an installer image disk for the VirtualBox emulator using the command:
+
+A4. Build a VirtualBox installer image
+       cd $HOME/AOSP
+        source build/envsetup.sh
+        lunch generic_x86-eng
+        make -j8 installer_vdi
+
diff --git a/build/target/board/generic_x86/disk_layout.conf b/build/target/board/generic_x86/disk_layout.conf
new file mode 100644 (file)
index 0000000..7b073ee
--- /dev/null
@@ -0,0 +1,54 @@
+device {
+    path /dev/block/sda
+
+    scheme mbr
+
+    # bytes in a disk sector (== 1 LBA), must be a power of 2!
+    sector_size 512
+
+    # What LBA should the partitions start at?
+    start_lba 2048
+
+    # Autodetect disk size if == 0
+    num_lba 0
+
+    partitions {
+        sysloader {
+            active y
+            type linux
+            len 7M
+        }
+
+        recovery {
+            active y
+            type linux
+            len 16M
+        }
+
+        boot {
+            active y
+            type linux
+            len 8M
+        }
+
+        cache {
+            type linux
+            len 512M
+        }
+
+        system {
+            type linux
+            len 512M
+        }
+
+        third_party {
+            type linux
+            len 512M
+        }
+
+        data {
+            type linux
+            len -1
+        }
+    }
+}
diff --git a/build/target/board/generic_x86/init.rc b/build/target/board/generic_x86/init.rc
new file mode 100644 (file)
index 0000000..8f6be28
--- /dev/null
@@ -0,0 +1,427 @@
+on early-init
+    start ueventd
+
+on init
+
+sysclktz 0
+
+loglevel 3
+
+# setup the global environment
+    export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
+    export LD_LIBRARY_PATH /vendor/lib:/system/lib
+    export ANDROID_BOOTLOGO 1
+    export ANDROID_ROOT /system
+    export ANDROID_ASSETS /system/app
+    export ANDROID_DATA /data
+    export EXTERNAL_STORAGE /mnt/sdcard
+    export ASEC_MOUNTPOINT /mnt/asec
+    export LOOP_MOUNTPOINT /mnt/obb
+    export BOOTCLASSPATH /system/framework/core.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/core-junit.jar
+
+# Backward compatibility
+    symlink /system/etc /etc
+    symlink /sys/kernel/debug /d
+
+# Right now vendor lives on the same filesystem as system,
+# but someday that may change.
+    symlink /system/vendor /vendor
+
+# create mountpoints
+    mkdir /mnt 0775 root system
+    mkdir /mnt/sdcard 0000 system system
+
+# Create cgroup mount point for cpu accounting
+    mkdir /acct
+    mount cgroup none /acct cpuacct
+    mkdir /acct/uid
+
+# Backwards Compat - XXX: Going away in G*
+    symlink /mnt/sdcard /sdcard
+
+    mkdir /system
+    mkdir /data 0771 system system
+    mkdir /cache 0770 system cache
+    mkdir /config 0500 root root
+
+    # Directory for putting things only root should see.
+    mkdir /mnt/secure 0700 root root
+
+    # Directory for staging bindmounts
+    mkdir /mnt/secure/staging 0700 root root
+
+    # Directory-target for where the secure container
+    # imagefile directory will be bind-mounted
+    mkdir /mnt/secure/asec  0700 root root
+
+    # Secure container public mount points.
+    mkdir /mnt/asec  0700 root system
+    mount tmpfs tmpfs /mnt/asec mode=0755,gid=1000
+
+    # Filesystem image public mount points.
+    mkdir /mnt/obb 0700 root system
+    mount tmpfs tmpfs /mnt/obb mode=0755,gid=1000
+
+    write /proc/sys/kernel/panic_on_oops 1
+    write /proc/sys/kernel/hung_task_timeout_secs 0
+    write /proc/cpu/alignment 4
+    write /proc/sys/kernel/sched_latency_ns 10000000
+    write /proc/sys/kernel/sched_wakeup_granularity_ns 2000000
+    write /proc/sys/kernel/sched_compat_yield 1
+    write /proc/sys/kernel/sched_child_runs_first 0
+
+# Create cgroup mount points for process groups
+    mkdir /dev/cpuctl
+    mount cgroup none /dev/cpuctl cpu
+    chown system system /dev/cpuctl
+    chown system system /dev/cpuctl/tasks
+    chmod 0777 /dev/cpuctl/tasks
+    write /dev/cpuctl/cpu.shares 1024
+
+    mkdir /dev/cpuctl/fg_boost
+    chown system system /dev/cpuctl/fg_boost/tasks
+    chmod 0777 /dev/cpuctl/fg_boost/tasks
+    write /dev/cpuctl/fg_boost/cpu.shares 1024
+
+    mkdir /dev/cpuctl/bg_non_interactive
+    chown system system /dev/cpuctl/bg_non_interactive/tasks
+    chmod 0777 /dev/cpuctl/bg_non_interactive/tasks
+    # 5.0 %
+    write /dev/cpuctl/bg_non_interactive/cpu.shares 52
+
+on fs
+# mount mtd partitions
+    mount ext4 /dev/block/sda6 /system rw
+    mkdir /system/vendor
+    mount ext4 /dev/block/sda8 /data nosuid nodev
+    mount ext4 /dev/block/sda7 /cache nosuid nodev
+
+on post-fs
+    # once everything is setup, no need to modify /
+    mount rootfs rootfs / ro remount
+
+    # We chown/chmod /data again so because mount is run as root + defaults
+    chown system system /data
+    chmod 0771 /data
+
+    # Create dump dir and collect dumps.
+    # Do this before we mount cache so eventually we can use cache for
+    # storing dumps on platforms which do not have a dedicated dump partition.
+   
+    mkdir /data/dontpanic
+    chown root log /data/dontpanic
+    chmod 0750 /data/dontpanic
+
+    # Collect apanic data, free resources and re-arm trigger
+    copy /proc/apanic_console /data/dontpanic/apanic_console
+    chown root log /data/dontpanic/apanic_console
+    chmod 0640 /data/dontpanic/apanic_console
+
+    copy /proc/apanic_threads /data/dontpanic/apanic_threads
+    chown root log /data/dontpanic/apanic_threads
+    chmod 0640 /data/dontpanic/apanic_threads
+
+    write /proc/apanic_console 1
+
+    # Same reason as /data above
+    chown system cache /cache
+    chmod 0770 /cache
+
+    # This may have been created by the recovery system with odd permissions
+    chown system cache /cache/recovery
+    chmod 0770 /cache/recovery
+
+    #change permissions on vmallocinfo so we can grab it from bugreports
+    chown root log /proc/vmallocinfo
+    chmod 0440 /proc/vmallocinfo
+
+    #change permissions on kmsg & sysrq-trigger so bugreports can grab kthread stacks
+    chown root system /proc/kmsg
+    chmod 0440 /proc/kmsg
+    chown root system /proc/sysrq-trigger
+    chmod 0220 /proc/sysrq-trigger
+
+# create basic filesystem structure
+    mkdir /data/misc 01771 system misc
+    mkdir /data/misc/bluetoothd 0770 bluetooth bluetooth
+    mkdir /data/misc/bluetooth 0770 system system
+    mkdir /data/misc/keystore 0700 keystore keystore
+    mkdir /data/misc/vpn 0770 system system
+    mkdir /data/misc/systemkeys 0700 system system
+    mkdir /data/misc/vpn/profiles 0770 system system
+    # give system access to wpa_supplicant.conf for backup and restore
+    mkdir /data/misc/wifi 0770 wifi wifi
+    chmod 0770 /data/misc/wifi
+    chmod 0660 /data/misc/wifi/wpa_supplicant.conf
+    mkdir /data/local 0771 shell shell
+    mkdir /data/local/tmp 0771 shell shell
+    mkdir /data/data 0771 system system
+    mkdir /data/app-private 0771 system system
+    mkdir /data/app 0771 system system
+    mkdir /data/property 0700 root root
+
+    # create dalvik-cache and double-check the perms
+    mkdir /data/dalvik-cache 0771 system system
+    chown system system /data/dalvik-cache
+    chmod 0771 /data/dalvik-cache
+
+    # create the lost+found directories, so as to enforce our permissions
+    mkdir /data/lost+found 0770
+    mkdir /cache/lost+found 0770
+
+    # double check the perms, in case lost+found already exists, and set owner
+    chown root root /data/lost+found
+    chmod 0770 /data/lost+found
+    chown root root /cache/lost+found
+    chmod 0770 /cache/lost+found
+
+    # create data/drm directory
+    mkdir /data/drm 0774 drm drm
+    chown drm drm /data/drm
+    chmod 0774 /data/drm
+
+on boot
+# basic network init
+    ifup lo
+    hostname localhost
+    domainname localdomain
+
+# set RLIMIT_NICE to allow priorities from 19 to -20
+    setrlimit 13 40 40
+
+# Define the oom_adj values for the classes of processes that can be
+# killed by the kernel.  These are used in ActivityManagerService.
+    setprop ro.FOREGROUND_APP_ADJ 0
+    setprop ro.VISIBLE_APP_ADJ 1
+    setprop ro.PERCEPTIBLE_APP_ADJ 2
+    setprop ro.HEAVY_WEIGHT_APP_ADJ 3
+    setprop ro.SECONDARY_SERVER_ADJ 4
+    setprop ro.BACKUP_APP_ADJ 5
+    setprop ro.HOME_APP_ADJ 6
+    setprop ro.HIDDEN_APP_MIN_ADJ 7
+    setprop ro.EMPTY_APP_ADJ 15
+
+# Define the memory thresholds at which the above process classes will
+# be killed.  These numbers are in pages (4k).
+    setprop ro.FOREGROUND_APP_MEM 2048
+    setprop ro.VISIBLE_APP_MEM 3072
+    setprop ro.PERCEPTIBLE_APP_MEM 4096
+    setprop ro.HEAVY_WEIGHT_APP_MEM 4096
+    setprop ro.SECONDARY_SERVER_MEM 6144
+    setprop ro.BACKUP_APP_MEM 6144
+    setprop ro.HOME_APP_MEM 6144
+    setprop ro.HIDDEN_APP_MEM 7168
+    setprop ro.EMPTY_APP_MEM 8192
+
+# Write value must be consistent with the above properties.
+# Note that the driver only supports 6 slots, so we have combined some of
+# the classes into the same memory level; the associated processes of higher
+# classes will still be killed first.
+    write /sys/module/lowmemorykiller/parameters/adj 0,1,2,4,7,15
+
+    write /proc/sys/vm/overcommit_memory 1
+    write /proc/sys/vm/min_free_order_shift 4
+    write /sys/module/lowmemorykiller/parameters/minfree 2048,3072,4096,6144,7168,8192
+
+    # Set init its forked children's oom_adj.
+    write /proc/1/oom_adj -16
+
+    # Tweak background writeout
+    write /proc/sys/vm/dirty_expire_centisecs 200
+    write /proc/sys/vm/dirty_background_ratio  5
+
+    # Permissions for System Server and daemons.
+    chown radio system /sys/android_power/state
+    chown radio system /sys/android_power/request_state
+    chown radio system /sys/android_power/acquire_full_wake_lock
+    chown radio system /sys/android_power/acquire_partial_wake_lock
+    chown radio system /sys/android_power/release_wake_lock
+    chown radio system /sys/power/state
+    chown radio system /sys/power/wake_lock
+    chown radio system /sys/power/wake_unlock
+    chmod 0660 /sys/power/state
+    chmod 0660 /sys/power/wake_lock
+    chmod 0660 /sys/power/wake_unlock
+    chown system system /sys/class/timed_output/vibrator/enable
+    chown system system /sys/class/leds/keyboard-backlight/brightness
+    chown system system /sys/class/leds/lcd-backlight/brightness
+    chown system system /sys/class/leds/button-backlight/brightness
+    chown system system /sys/class/leds/jogball-backlight/brightness
+    chown system system /sys/class/leds/red/brightness
+    chown system system /sys/class/leds/green/brightness
+    chown system system /sys/class/leds/blue/brightness
+    chown system system /sys/class/leds/red/device/grpfreq
+    chown system system /sys/class/leds/red/device/grppwm
+    chown system system /sys/class/leds/red/device/blink
+    chown system system /sys/class/leds/red/brightness
+    chown system system /sys/class/leds/green/brightness
+    chown system system /sys/class/leds/blue/brightness
+    chown system system /sys/class/leds/red/device/grpfreq
+    chown system system /sys/class/leds/red/device/grppwm
+    chown system system /sys/class/leds/red/device/blink
+    chown system system /sys/class/timed_output/vibrator/enable
+    chown system system /sys/module/sco/parameters/disable_esco
+    chown system system /sys/kernel/ipv4/tcp_wmem_min
+    chown system system /sys/kernel/ipv4/tcp_wmem_def
+    chown system system /sys/kernel/ipv4/tcp_wmem_max
+    chown system system /sys/kernel/ipv4/tcp_rmem_min
+    chown system system /sys/kernel/ipv4/tcp_rmem_def
+    chown system system /sys/kernel/ipv4/tcp_rmem_max
+    chown root radio /proc/cmdline
+
+# Define TCP buffer sizes for various networks
+#   ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax,
+    setprop net.tcp.buffersize.default 4096,87380,110208,4096,16384,110208
+    setprop net.tcp.buffersize.wifi    4095,87380,110208,4096,16384,110208
+    setprop net.tcp.buffersize.umts    4094,87380,110208,4096,16384,110208
+    setprop net.tcp.buffersize.edge    4093,26280,35040,4096,16384,35040
+    setprop net.tcp.buffersize.gprs    4092,8760,11680,4096,8760,11680
+
+    class_start default
+
+## Daemon processes to be run by init.
+##
+service ueventd /sbin/ueventd
+    critical
+
+service console /system/bin/sh
+    console
+    disabled
+    user shell
+    group log
+
+on property:ro.secure=0
+    start console
+
+# Enable networking so that adb can connect
+service netcfg /system/bin/netcfg eth0 dhcp
+    setprop property:ro.kernel.qemu 1
+    oneshot
+
+# adbd is controlled by the persist.service.adb.enable system property
+service adbd /sbin/adbd
+    disabled
+
+# adbd on at boot in emulator
+on property:ro.kernel.qemu=1
+    start adbd
+
+on property:persist.service.adb.enable=1
+    start adbd
+
+on property:persist.service.adb.enable=0
+    stop adbd
+
+service servicemanager /system/bin/servicemanager
+    user system
+    critical
+    onrestart restart zygote
+    onrestart restart media
+
+service vold /system/bin/vold
+    socket vold stream 0660 root mount
+    ioprio be 2
+
+service netd /system/bin/netd
+    socket netd stream 0660 root system
+    socket dnsproxyd stream 0660 root inet
+
+service debuggerd /system/bin/debuggerd
+
+service ril-daemon /system/bin/rild
+    socket rild stream 660 root radio
+    socket rild-debug stream 660 radio system
+    user root
+    group radio cache inet misc audio sdcard_rw
+
+service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
+    socket zygote stream 666
+    onrestart write /sys/android_power/request_state wake
+    onrestart write /sys/power/state on
+    onrestart restart media
+    onrestart restart netd
+
+service drm /system/bin/drmserver
+    user drm
+    group system root inet
+
+service drmio /system/bin/drmioserver
+    user drmio
+
+service media /system/bin/mediaserver
+    user media
+    group system audio camera graphics inet net_bt net_bt_admin net_raw
+    ioprio rt 4
+
+service bootanim /system/bin/bootanimation
+    user graphics
+    group graphics
+    disabled
+    oneshot
+
+service dbus /system/bin/dbus-daemon --system --nofork
+    socket dbus stream 660 bluetooth bluetooth
+    user bluetooth
+    group bluetooth net_bt_admin
+
+service bluetoothd /system/bin/bluetoothd -n
+    socket bluetooth stream 660 bluetooth bluetooth
+    socket dbus_bluetooth stream 660 bluetooth bluetooth
+    # init.rc does not yet support applying capabilities, so run as root and
+    # let bluetoothd drop uid to bluetooth with the right linux capabilities
+    group bluetooth net_bt_admin misc
+    disabled
+
+service hfag /system/bin/sdptool add --channel=10 HFAG
+    user bluetooth
+    group bluetooth net_bt_admin
+    disabled
+    oneshot
+
+service hsag /system/bin/sdptool add --channel=11 HSAG
+    user bluetooth
+    group bluetooth net_bt_admin
+    disabled
+    oneshot
+
+service opush /system/bin/sdptool add --channel=12 OPUSH
+    user bluetooth
+    group bluetooth net_bt_admin
+    disabled
+    oneshot
+
+service pbap /system/bin/sdptool add --channel=19 PBAP
+    user bluetooth
+    group bluetooth net_bt_admin
+    disabled
+    oneshot
+
+service installd /system/bin/installd
+    socket installd stream 600 system system
+
+service flash_recovery /system/etc/install-recovery.sh
+    oneshot
+
+service racoon /system/bin/racoon
+    socket racoon stream 600 system system
+    # racoon will setuid to vpn after getting necessary resources.
+    group net_admin
+    disabled
+    oneshot
+
+service mtpd /system/bin/mtpd
+    socket mtpd stream 600 system system
+    user vpn
+    group vpn net_admin net_raw
+    disabled
+    oneshot
+
+service keystore /system/bin/keystore /data/misc/keystore
+    user keystore
+    group keystore
+    socket keystore stream 666
+
+service dumpstate /system/bin/dumpstate -s
+    socket dumpstate stream 0660 shell log
+    disabled
+    oneshot
diff --git a/build/target/board/sim/AndroidBoard.mk b/build/target/board/sim/AndroidBoard.mk
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/build/target/board/sim/BoardConfig.mk b/build/target/board/sim/BoardConfig.mk
new file mode 100644 (file)
index 0000000..ba25c18
--- /dev/null
@@ -0,0 +1,31 @@
+# config.mk
+# 
+# Product-specific compile-time definitions.
+#
+
+# Don't try prelinking or compressing the shared libraries
+# used by the simulator.  The host OS won't know what to do
+# with them, and they may not even be ELF files.
+#
+# These definitions override the defaults in config/config.make.
+TARGET_COMPRESS_MODULE_SYMBOLS := false
+TARGET_PRELINK_MODULE := false
+
+# Don't try to build a bootloader.
+TARGET_NO_BOOTLOADER := true
+
+# Don't bother with a kernel
+TARGET_NO_KERNEL := true
+
+# The simulator does not support native code at all
+TARGET_CPU_ABI := none
+
+# But it is very likely SMP.
+TARGET_CPU_SMP := true
+
+#the simulator partially emulates the original HTC /dev/eac audio interface
+HAVE_HTC_AUDIO_DRIVER := true
+BOARD_USES_GENERIC_AUDIO := true
+
+# no hardware camera
+USE_CAMERA_STUB := true
diff --git a/build/target/product/AndroidProducts.mk b/build/target/product/AndroidProducts.mk
new file mode 100644 (file)
index 0000000..32416c5
--- /dev/null
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# This file should set PRODUCT_MAKEFILES to a list of product makefiles
+# to expose to the build system.  LOCAL_DIR will already be set to
+# the directory containing this file.
+#
+# This file may not rely on the value of any variable other than
+# LOCAL_DIR; do not use any conditionals, and do not look up the
+# value of any variable that isn't set in this file or in a file that
+# it includes.
+#
+
+# Unbundled apps will be built with the default product config.
+ifneq ($(TARGET_BUILD_APPS),)
+PRODUCT_MAKEFILES := \
+    $(LOCAL_DIR)/core.mk \
+    $(LOCAL_DIR)/generic.mk \
+    $(LOCAL_DIR)/full.mk
+else
+PRODUCT_MAKEFILES := \
+    $(LOCAL_DIR)/core.mk \
+    $(LOCAL_DIR)/generic.mk \
+    $(LOCAL_DIR)/generic_x86.mk \
+    $(LOCAL_DIR)/full.mk \
+    $(LOCAL_DIR)/full_x86.mk \
+    $(LOCAL_DIR)/sdk.mk \
+    $(LOCAL_DIR)/sim.mk
+endif
diff --git a/build/target/product/core.mk b/build/target/product/core.mk
new file mode 100644 (file)
index 0000000..55d6c26
--- /dev/null
@@ -0,0 +1,87 @@
+#
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+PRODUCT_BRAND := generic
+PRODUCT_DEVICE := generic
+PRODUCT_NAME := core
+
+PRODUCT_PROPERTY_OVERRIDES := \
+    ro.config.notification_sound=OnTheHunt.ogg \
+    ro.config.alarm_alert=Alarm_Classic.ogg
+
+PRODUCT_PACKAGES := \
+    bouncycastle \
+    com.android.location.provider \
+    com.android.location.provider.xml \
+    core \
+    core-junit \
+    create_test_dmtrace \
+    dalvikvm \
+    dexdeps \
+    dexdump \
+    dexlist \
+    dexopt \
+    dmtracedump \
+    dvz \
+    dx \
+    ext \
+    framework-res \
+    hprof-conv \
+    icu.dat \
+    ip-up-vpn \
+    jasmin \
+    jasmin.jar \
+    libcrypto \
+    libdex \
+    libdvm \
+    libexpat \
+    libicui18n \
+    libicuuc \
+    libjavacore \
+    libnativehelper \
+    libnfc_ndef \
+    libsqlite_jni \
+    libssl \
+    libz \
+    sqlite-jdbc \
+    Browser \
+    Contacts \
+    Home \
+    HTMLViewer \
+    Phone \
+    ApplicationsProvider \
+    ContactsProvider \
+    DownloadProvider \
+    DownloadProviderUi \
+    MediaProvider \
+    PicoTts \
+    SettingsProvider \
+    TelephonyProvider \
+    TtsService \
+    VpnServices \
+    UserDictionaryProvider \
+    PackageInstaller \
+    DefaultContainerService \
+    Bugreport
+
+# host-only dependencies
+ifeq ($(WITH_HOST_DALVIK),true)
+    PRODUCT_PACKAGES += \
+        bouncycastle-hostdex \
+        core-hostdex \
+        libjavacore-host
+endif
+
diff --git a/build/target/product/full.mk b/build/target/product/full.mk
new file mode 100644 (file)
index 0000000..c563bcc
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This is a build configuration for a full-featured build of the
+# Open-Source part of the tree. It's geared toward a US-centric
+# build quite specifically for the emulator, and might not be
+# entirely appropriate to inherit from for on-device configurations.
+
+$(call inherit-product, $(SRC_TARGET_DIR)/product/full_base.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/board/generic/device.mk)
+
+# Overrides
+PRODUCT_NAME := full
+PRODUCT_DEVICE := generic
+PRODUCT_BRAND := Android
+PRODUCT_MODEL := Full Android on Emulator
diff --git a/build/target/product/full_base.mk b/build/target/product/full_base.mk
new file mode 100644 (file)
index 0000000..fb9b528
--- /dev/null
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This is a build configuration for a full-featured build of the
+# Open-Source part of the tree. This is a base configuration to
+# bes used for AOSP builds on various target devices.
+
+PRODUCT_PACKAGES := \
+    OpenWnn \
+    PinyinIME \
+    VoiceDialer \
+    libWnnEngDic \
+    libWnnJpnDic \
+    libwnndict
+
+# Additional settings used in all AOSP builds
+PRODUCT_PROPERTY_OVERRIDES := \
+    keyguard.no_require_sim=true \
+    ro.com.android.dateformat=MM-dd-yyyy \
+    ro.com.android.dataroaming=true \
+    ro.config.ringtone=Ring_Synth_04.ogg \
+    ro.config.notification_sound=pixiedust.ogg
+
+# Put en_US first in the list, to make it default.
+PRODUCT_LOCALES := en_US
+
+# Get some sounds
+$(call inherit-product-if-exists, frameworks/base/data/sounds/AllAudio.mk)
+
+# Get the TTS language packs
+$(call inherit-product-if-exists, external/svox/pico/lang/all_pico_languages.mk)
+
+# Get the list of languages.
+$(call inherit-product, $(SRC_TARGET_DIR)/product/locales_full.mk)
+
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic.mk)
diff --git a/build/target/product/full_x86.mk b/build/target/product/full_x86.mk
new file mode 100644 (file)
index 0000000..affdc13
--- /dev/null
@@ -0,0 +1,34 @@
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This is a build configuration for a full-featured build of the
+# Open-Source part of the tree. It's geared toward a US-centric
+# x86 build, but all those aspects can be overridden
+# in inherited configurations.
+
+# If running on an emulator or some other device that has a LAN connection
+# that isn't a wifi connection. This will instruct init.rc to enable the
+# network connection so that you can use it with ADB
+ifdef NET_ETH0_STARTONBOOT
+  PRODUCT_PROPERTY_OVERRIDES += net.eth0.startonboot=1
+endif
+
+$(call inherit-product, build/target/product/full.mk)
+
+# Overrides
+PRODUCT_NAME := full_x86
+PRODUCT_DEVICE := generic_x86
+PRODUCT_MODEL := Full Android x86
diff --git a/build/target/product/generic.mk b/build/target/product/generic.mk
new file mode 100644 (file)
index 0000000..eed354a
--- /dev/null
@@ -0,0 +1,51 @@
+#
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This is a generic product that isn't specialized for a specific device.
+# It includes the base Android platform.
+
+PRODUCT_PACKAGES := \
+    AccountAndSyncSettings \
+    DeskClock \
+    AlarmProvider \
+    Bluetooth \
+    Calculator \
+    Calendar \
+    Camera \
+    CertInstaller \
+    DrmProvider \
+    Email \
+    Gallery3D \
+    LatinIME \
+    Launcher2 \
+    Mms \
+    Music \
+    Provision \
+    Protips \
+    QuickSearchBox \
+    Settings \
+    Sync \
+    SystemUI \
+    Updater \
+    CalendarProvider \
+    SyncProvider
+
+$(call inherit-product, $(SRC_TARGET_DIR)/product/core.mk)
+
+# Overrides
+PRODUCT_BRAND := generic
+PRODUCT_DEVICE := generic
+PRODUCT_NAME := generic
diff --git a/build/target/product/generic_x86.mk b/build/target/product/generic_x86.mk
new file mode 100644 (file)
index 0000000..345a79a
--- /dev/null
@@ -0,0 +1,34 @@
+# This is a generic product that isn't specialized for a specific device.
+# It includes the base Android platform. If you need Google-specific features,
+# you should derive from generic_with_google.mk
+
+PRODUCT_PACKAGES := \
+    DeskClock \
+    AlarmProvider \
+    Calendar \
+    Camera \
+    DrmProvider \
+    LatinIME \
+    Mms \
+    Music \
+    Settings \
+    Sync \
+    Updater \
+    CalendarProvider \
+    SubscribedFeedsProvider \
+    SyncProvider
+
+$(call inherit-product, $(SRC_TARGET_DIR)/product/core.mk)
+
+# Overrides
+PRODUCT_BRAND := generic_x86
+PRODUCT_DEVICE := generic_x86
+PRODUCT_NAME := generic_x86
+PRODUCT_POLICY := android.policy_phone
+
+# If running on an emulator or some other device that has a LAN connection
+# that isn't a wifi connection. This will instruct init.rc to enable the
+# network connection so that you can use it with ADB
+ifdef NET_ETH0_STARTONBOOT
+  PRODUCT_PROPERTY_OVERRIDES += net.eth0.startonboot=1
+endif
diff --git a/build/target/product/languages_full.mk b/build/target/product/languages_full.mk
new file mode 100644 (file)
index 0000000..6c49c79
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This is a build configuration that just contains a list of languages.
+# It helps in situations where laugnages must come first in the list,
+# mostly because screen densities interfere with the list of locales and
+# the system misbehaves when a density is the first locale.
+
+# Those are all the locales that have translations.
+PRODUCT_LOCALES := en_US en_GB fr_FR it_IT es_ES es_US de_DE nl_NL cs_CZ pl_PL zh_TW zh_CN ru_RU ko_KR nb_NO pt_PT pt_BR da_DK el_GR sv_SE tr_TR ja_JP
diff --git a/build/target/product/languages_small.mk b/build/target/product/languages_small.mk
new file mode 100644 (file)
index 0000000..d695ca8
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This is a build configuration that just contains a list of languages.
+# It helps in situations where laugnages must come first in the list,
+# mostly because screen densities interfere with the list of locales and
+# the system misbehaves when a density is the first locale.
+
+# This is the list of languages that originally shipped on ADP1
+
+PRODUCT_LOCALES := en_US en_GB fr_FR it_IT de_DE es_ES
diff --git a/build/target/product/locales_full.mk b/build/target/product/locales_full.mk
new file mode 100644 (file)
index 0000000..cf10392
--- /dev/null
@@ -0,0 +1,5 @@
+# The locales from the ICU "-large.dat" data set.
+# See external/icu4c/stubdata.
+# This is distinct from "languages_full.mk", which contains those locales for
+# which we have translations. If you like, this file is i18n rather than l18n.
+PRODUCT_LOCALES := cs_CZ da_DK de_AT de_CH de_DE de_LI el_GR en_AU en_CA en_GB en_NZ en_SG en_US es_ES fr_CA fr_CH fr_BE fr_FR it_CH it_IT ja_JP ko_KR nb_NO nl_BE nl_NL pl_PL pt_PT ru_RU sv_SE tr_TR zh_CN zh_HK zh_TW
diff --git a/build/target/product/sdk.mk b/build/target/product/sdk.mk
new file mode 100644 (file)
index 0000000..7a986bd
--- /dev/null
@@ -0,0 +1,196 @@
+#
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+PRODUCT_PROPERTY_OVERRIDES :=
+
+PRODUCT_PACKAGES := \
+       SystemUI \
+       AccountAndSyncSettings \
+       Camera \
+       Calculator \
+       DeskClock \
+       Development \
+       DrmProvider \
+       Email \
+       Fallback \
+       Gallery \
+       GPSEnable \
+       Launcher2 \
+       Protips \
+       Music \
+       Mms \
+       Settings \
+       SdkSetup \
+       CustomLocale \
+       gpstest \
+       sqlite3 \
+       LatinIME \
+       PinyinIME \
+       OpenWnn \
+       libWnnEngDic \
+       libWnnJpnDic \
+       libwnndict \
+       CertInstaller \
+       LiveWallpapersPicker \
+       ApiDemos \
+       GestureBuilder \
+       SoftKeyboard \
+       CubeLiveWallpapers \
+       QuickSearchBox \
+        monkeyrunner \
+        guavalib \
+        jsr305lib \
+       jython \
+        jsilver
+
+# Host tools that are parts of the SDK.
+# See development/build/sdk.atree
+PRODUCT_PACKAGES += \
+       adb \
+       dmtracedump \
+       etc1tool \
+       hprof-conv \
+       mksdcard \
+       emulator \
+       ddms \
+       hierarchyviewer \
+       draw9patch \
+       layoutopt \
+       traceview \
+       android \
+       dexdump \
+        monkeyrunner
+
+# Native host Java libraries that are parts of the SDK.
+# See development/build/sdk.atree
+PRODUCT_PACKAGES += \
+       androidprefs \
+       sdkstats \
+       archquery \
+       ddms \
+       ddmlib \
+       ddmuilib \
+       hierarchyviewer \
+       draw9patch \
+       layoutopt \
+       uix \
+       traceview \
+       anttasks \
+       sdklib \
+       sdkuilib \
+       sdkmanager \
+       swing-worker-1.1 \
+       groovy-all-1.7.0 \
+       commons-compress-1.0 \
+       emmalib \
+       org-netbeans-api-visual \
+       org-openide-util \
+       jcommon-1.0.12 \
+       jfreechart-1.0.9 \
+       jfreechart-1.0.9-swt \
+       org.eclipse.core.commands_3.4.0.I20080509-2000 \
+       org.eclipse.equinox.common_3.4.0.v20080421-2006 \
+       org.eclipse.jface_3.4.2.M20090107-0800 \
+       osgi \
+       layoutlib \
+        monkeyrunner \
+        guavalib \
+        jsr305lib \
+       jython
+
+PRODUCT_PACKAGE_OVERLAYS := development/sdk_overlay
+
+PRODUCT_COPY_FILES := \
+       system/core/rootdir/etc/vold.fstab:system/etc/vold.fstab \
+       frameworks/base/data/sounds/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
+       frameworks/base/data/sounds/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
+       frameworks/base/data/etc/android.hardware.camera.autofocus.xml:system/etc/permissions/android.hardware.camera.autofocus.xml
+
+$(call inherit-product, $(SRC_TARGET_DIR)/product/core.mk)
+
+# Overrides
+PRODUCT_BRAND := generic
+PRODUCT_NAME := sdk
+PRODUCT_DEVICE := generic
+PRODUCT_LOCALES := \
+       ldpi \
+       hdpi \
+       mdpi \
+       ar_EG \
+       ar_IL \
+       bg_BG \
+       ca_ES \
+       cs_CZ \
+       da_DK \
+       de_AT \
+       de_CH \
+       de_DE \
+       de_LI \
+       el_GR \
+       en_AU \
+       en_CA \
+       en_GB \
+       en_IE \
+       en_IN \
+       en_NZ \
+       en_SG \
+       en_US \
+       en_ZA \
+       es_ES \
+       es_US \
+       fi_FI \
+       fr_BE \
+       fr_CA \
+       fr_CH \
+       fr_FR \
+       he_IL \
+       hi_IN \
+       hr_HR \
+       hu_HU \
+       id_ID \
+       it_CH \
+       it_IT \
+       ja_JP \
+       ko_KR \
+       lt_LT \
+       lv_LV \
+       nb_NO \
+       nl_BE \
+       nl_NL \
+       pl_PL \
+       pt_BR \
+       pt_PT \
+       ro_RO \
+       ru_RU \
+       sk_SK \
+       sl_SI \
+       sr_RS \
+       sv_SE \
+       th_TH \
+       tl_PH \
+       tr_TR \
+       uk_UA \
+       vi_VN \
+       zh_CN \
+       zh_TW
+
+# include available languages for TTS in the system image
+include external/svox/pico/lang/PicoLangDeDeInSystem.mk
+include external/svox/pico/lang/PicoLangEnGBInSystem.mk
+include external/svox/pico/lang/PicoLangEnUsInSystem.mk
+include external/svox/pico/lang/PicoLangEsEsInSystem.mk
+include external/svox/pico/lang/PicoLangFrFrInSystem.mk
+include external/svox/pico/lang/PicoLangItItInSystem.mk
diff --git a/build/target/product/security/README b/build/target/product/security/README
new file mode 100644 (file)
index 0000000..24f984c
--- /dev/null
@@ -0,0 +1,34 @@
+The following commands were used to generate the test key pairs:
+
+  development/tools/make_key testkey  '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
+  development/tools/make_key platform '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
+  development/tools/make_key shared   '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
+  development/tools/make_key media    '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
+
+The following standard test keys are currently included:
+
+testkey -- a generic key for packages that do not otherwise specify a key.
+platform -- a test key for packages that are part of the core platform.
+shared -- a test key for things that are shared in the home/contacts process.
+media -- a test key for packages that are part of the media/download system.
+
+These test keys are used strictly in development, and should never be assumed
+to convey any sort of validity.  When $BUILD_SECURE=true, the code should not
+honor these keys in any context.
+
+
+signing using the openssl commandline (for boot/system images)
+--------------------------------------------------------------
+
+1. convert pk8 format key to pem format
+   % openssl pkcs8 -inform DER -nocrypt -in testkey.pk8 -out testkey.pem
+
+2. create a signature using the pem format key
+   % openssl dgst -binary -sha1 -sign testkey.pem FILE > FILE.sig
+
+extracting public keys for embedding
+------------------------------------
+it's a Java tool
+but it generates C code
+take a look at commands/recovery/Android.mk
+you'll see it running $(HOST_OUT_JAVA_LIBRARIES)/dumpkey.jar
diff --git a/build/target/product/security/media.pk8 b/build/target/product/security/media.pk8
new file mode 100644 (file)
index 0000000..a6db9ba
Binary files /dev/null and b/build/target/product/security/media.pk8 differ
diff --git a/build/target/product/security/media.x509.pem b/build/target/product/security/media.x509.pem
new file mode 100644 (file)
index 0000000..98cd443
--- /dev/null
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEqDCCA5CgAwIBAgIJAPK5jmEjVyxOMA0GCSqGSIb3DQEBBAUAMIGUMQswCQYD
+VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
+VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE
+AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe
+Fw0wODA0MTUyMzQwNTdaFw0zNTA5MDEyMzQwNTdaMIGUMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G
+A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p
+ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI
+hvcNAQEBBQADggENADCCAQgCggEBAK4lDFoW75f8KGmsZRsyF8w2ug6GlkFo1YoE
+n0DOhYZxI6P/tPbZScM88to6BcI+rKpX2AOImxdZvPWefG8hiQriUIW37VaqYmwJ
+ie+czTY2LKDo0blgP9TYModnkmzMCQxot3Wuf/MJNMw2nvKFWiZn3wxmf9DHz12O
+umVYBnNzA7tiRybquu37cvB+16dqs8uaOBxLfc2AmxQNiR8AITvkAfWNagamHq3D
+qcLxxlZyhbCa4JNCpm+kIer5Ot91c6AowzHXBgGrOvfMhAM+znx3KjpbhrDb6dd3
+w6SKqYAe3O4ngVifRNnkETl5YAV2qZQQuoEJElna2YxsaP94S48CAQOjgfwwgfkw
+HQYDVR0OBBYEFMopPKqLwO0+VC7vQgWiv/K1fk11MIHJBgNVHSMEgcEwgb6AFMop
+PKqLwO0+VC7vQgWiv/K1fk11oYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH
+QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG
+CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAPK5jmEjVyxOMAwGA1Ud
+EwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBAITelRbV5KhyF6c9qEhwSPUzc6X3
+M/OQ1hvfPMnlJRYlv8qnwxWcriddFyqa4eh21UWBJ6xUL2gpDdUQwAKdj1Hg7hVr
+e3tazbOUJBuOx4t05cQsXK+uFWyvW9GZojonUk2gct6743hGSlM2MLDk0P+34I7L
+cB+ttjecdEZ/bgDG7YiFlTgHkgOHVgB4csjjAHr0I6V6LKs6KChptkxLe9X8GH0K
+fiQVll1ark4Hpt91G0p16Xk8kYphK4HNC2KK7gFo3ETkexDTWTJghJ1q321yfcJE
+RMIh0/nsw2jK0HmZ8rgQW8HyDTjUEGbMFBHCV6lupDSfV0ZWVQfk6AIKGoE=
+-----END CERTIFICATE-----
diff --git a/build/target/product/security/platform.pk8 b/build/target/product/security/platform.pk8
new file mode 100644 (file)
index 0000000..e27a393
Binary files /dev/null and b/build/target/product/security/platform.pk8 differ
diff --git a/build/target/product/security/platform.x509.pem b/build/target/product/security/platform.x509.pem
new file mode 100644 (file)
index 0000000..087f02e
--- /dev/null
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEqDCCA5CgAwIBAgIJALOZgIbQVs/6MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYD
+VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
+VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE
+AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe
+Fw0wODA0MTUyMjQwNTBaFw0zNTA5MDEyMjQwNTBaMIGUMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G
+A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p
+ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI
+hvcNAQEBBQADggENADCCAQgCggEBAJx4BZKsDV04HN6qZezIpgBuNkgMbXIHsSAR
+vlCGOqvitV0Amt9xRtbyICKAx81Ne9smJDuKgGwms0sTdSOkkmgiSQTcAUk+fArP
+GgXIdPabA3tgMJ2QdNJCgOFrrSqHNDYZUer3KkgtCbIEsYdeEqyYwap3PWgAuer9
+5W1Yvtjo2hb5o2AJnDeoNKbf7be2tEoEngeiafzPLFSW8s821k35CjuNjzSjuqtM
+9TNxqydxmzulh1StDFP8FOHbRdUeI0+76TybpO35zlQmE1DsU1YHv2mi/0qgfbX3
+6iANCabBtJ4hQC+J7RGQiTqrWpGA8VLoL4WkV1PPX8GQccXuyCcCAQOjgfwwgfkw
+HQYDVR0OBBYEFE/koLPdnLop9x1yh8Tnw48ghsKZMIHJBgNVHSMEgcEwgb6AFE/k
+oLPdnLop9x1yh8Tnw48ghsKZoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH
+QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG
+CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJALOZgIbQVs/6MAwGA1Ud
+EwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBAFclUbjZOh9z3g9tRp+G2tZwFAAp
+PIigzXzXeLc9r8wZf6t25iEuVsHHYc/EL9cz3lLFCuCIFM78CjtaGkNGBU2Cnx2C
+tCsgSL+ItdFJKe+F9g7dEtctVWV+IuPoXQTIMdYT0Zk4u4mCJH+jISVroS0dao+S
+6h2xw3Mxe6DAN/DRr/ZFrvIkl5+6bnoUvAJccbmBOM7z3fwFlhfPJIRc97QNY4L3
+J17XOElatuWTG5QhdlxJG3L7aOCA29tYwgKdNHyLMozkPvaosVUz7fvpib1qSN1L
+IC7alMarjdW4OZID2q4u1EYjLk/pvZYTlMYwDlE448/Shebk5INTjLixs1c=
+-----END CERTIFICATE-----
diff --git a/build/target/product/security/shared.pk8 b/build/target/product/security/shared.pk8
new file mode 100644 (file)
index 0000000..cf99acd
Binary files /dev/null and b/build/target/product/security/shared.pk8 differ
diff --git a/build/target/product/security/shared.x509.pem b/build/target/product/security/shared.x509.pem
new file mode 100644 (file)
index 0000000..7f886a8
--- /dev/null
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEqDCCA5CgAwIBAgIJAPKnM5a9OHZ6MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYD
+VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
+VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE
+AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe
+Fw0wODA3MjMyMTU3NTlaFw0zNTEyMDkyMTU3NTlaMIGUMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G
+A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p
+ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI
+hvcNAQEBBQADggENADCCAQgCggEBAMjC2/0JSi30XD/xoy7SGAXscvxY0BeXG9D2
+tSwmLXCBnRkZZ+FY39Oix/Gz4OgM5UXXnShIIgIR64bw/YMS03tCDBE3UMyUYYro
+cvSIZGO9xGJ8qgwEg8hkk+NRVXEXAzi/3MTNat3RwKLzX1zyTtPkBDo+WOKwXmZM
+zeEry2dzX9bfEknDaeYlQrwKRynlORf1w4/6UtF7c8nHN5jdsY7UgVkIdVR+Zr/F
+2spMJabrlg7ZaSNwnaMCumRstJazJehsXIsuejN3srvkx88zJUKRFj9okVKsCIVQ
+yDxQj0v1rfCu1aLcoFg/mrCtF2UNt+6ksj/bRYhVR9D+q3IYOIkCAQOjgfwwgfkw
+HQYDVR0OBBYEFMtMfizbs/CtqY2reZaNFy6dux7RMIHJBgNVHSMEgcEwgb6AFMtM
+fizbs/CtqY2reZaNFy6dux7RoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH
+QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG
+CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAPKnM5a9OHZ6MAwGA1Ud
+EwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBAECo0JaZeVnpF6NsRCRra6wrrgVD
+fs2JeUEY94NHIDUtHG+KObCGmUL02mWYH6opUdM5cRKewZIdeVZxxSfW4knyUoKf
+r1tZExAxHi3gllANVorUEUplbcNKjG9hBFOvwep5ktukqns/hUOm41wHKN53/pfu
+rIN3H9DskPjkRJQ07gtgRXg+cMei5GAkkmDgA892CNw1Kkye9wbe9LJgUOl4ri//
+16MyN4cBSRXrPMh0/MeprpMId8XIx9HC4qjuhjyJGA0YVc7bpADnukPMyqckPTl+
+fA6Ojk19T5K2u+rUnAzwGAae3coufi+0Zo2J2715UNDNJUGA+h6q/CpVb4Q=
+-----END CERTIFICATE-----
diff --git a/build/target/product/security/testkey.pk8 b/build/target/product/security/testkey.pk8
new file mode 100644 (file)
index 0000000..586c1bd
Binary files /dev/null and b/build/target/product/security/testkey.pk8 differ
diff --git a/build/target/product/security/testkey.x509.pem b/build/target/product/security/testkey.x509.pem
new file mode 100644 (file)
index 0000000..e242d83
--- /dev/null
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD
+VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
+VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE
+AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe
+Fw0wODAyMjkwMTMzNDZaFw0zNTA3MTcwMTMzNDZaMIGUMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G
+A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p
+ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI
+hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM
+qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4
+wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy
+4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU
+RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s
+zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw
+HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ
+AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH
+QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG
+CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud
+EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHqvlozrUMRBBVEY0NqrrwFbinZa
+J6cVosK0TyIUFf/azgMJWr+kLfcHCHJsIGnlw27drgQAvilFLAhLwn62oX6snb4Y
+LCBOsVMR9FXYJLZW2+TcIkCRLXWG/oiVHQGo/rWuWkJgU134NDEFJCJGjDbiLCpe
++ZTWHdcwauTJ9pUbo8EvHRkU3cYfGmLaLfgn9gP+pWA7LFQNvXwBnDa6sppCccEX
+31I828XzgXpJ4O+mDL1/dBd+ek8ZPUP0IgdyZm5MTYPhvVqGCHzzTy3sIeJFymwr
+sBbmg2OAUNLEMO6nwmocSdN2ClirfxqCzJOLSDE4QyS9BAH6EhY6UFcOaE0=
+-----END CERTIFICATE-----
diff --git a/build/target/product/sim.mk b/build/target/product/sim.mk
new file mode 100644 (file)
index 0000000..09722d6
--- /dev/null
@@ -0,0 +1,6 @@
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/locales_full.mk)
+
+# Overrides
+PRODUCT_NAME := sim
+PRODUCT_DEVICE := sim
diff --git a/build/tools/Android.mk b/build/tools/Android.mk
new file mode 100644 (file)
index 0000000..fa9d0b7
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(my-dir)
+
+# If we're building only unbundled apps, this is the only tool we need.
+ifneq ($(TARGET_BUILD_APPS),)
+include $(LOCAL_PATH)/signapk/Android.mk
+else
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/build/tools/acp/Android.mk b/build/tools/acp/Android.mk
new file mode 100644 (file)
index 0000000..5e0e2e4
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2005 The Android Open Source Project
+#
+# Custom version of cp.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+       acp.c
+
+ifeq ($(HOST_OS),cygwin)
+LOCAL_CFLAGS += -DWIN32_EXE
+endif
+ifeq ($(HOST_OS),darwin)
+LOCAL_CFLAGS += -DMACOSX_RSRC
+endif
+ifeq ($(HOST_OS),linux)
+endif
+
+LOCAL_STATIC_LIBRARIES := libhost
+LOCAL_C_INCLUDES := build/libs/host/include
+LOCAL_MODULE := acp
+LOCAL_ACP_UNAVAILABLE := true
+
+include $(BUILD_HOST_EXECUTABLE)
+
diff --git a/build/tools/acp/README b/build/tools/acp/README
new file mode 100644 (file)
index 0000000..a1809d9
--- /dev/null
@@ -0,0 +1,40 @@
+README for Android "acp" Command
+
+The "cp" command was judged and found wanting.  The issues are:
+
+Mac OS X:
+ - Uses the BSD cp, not the fancy GNU cp.  It lacks the "-u" flag, which
+   only copies files if they are newer than the destination.  This can
+   slow the build when copying lots of content.
+ - Doesn't take the "-d" flag, which causes symlinks to be copied as
+   links.  This is the default behavior, so it's not all bad, but it
+   complains if you supply "-d".
+
+MinGW/Cygwin:
+ - Gets really weird when copying a file called "foo.exe", failing with
+   "cp: skipping file 'foo.exe', as it was replaced while being copied".
+   This only seems to happen when the source file is on an NFS/Samba
+   volume.  "cp" works okay copying from local disk.
+
+Linux:
+ - On some systems it's possible to have microsecond-accurate timestamps
+   on an NFS volume, and non-microsecond timestamps on a local volume.
+   If you copy from NFS to local disk, your NFS files will always be
+   newer, because the local disk time stamp is truncated rather than
+   rounded up.  This foils the "-u" flag if you also supply the "-p" flag
+   to preserve timestamps.
+ - The Darwin linker insists that ranlib be current.  If you copy the
+   library, the time stamp no longer matches.  Preserving the time
+   stamp is essential, so simply turning the "-p" flag off doesn't work.
+
+Futzing around these in make with GNU make functions is awkward at best.
+It's easier and more reliable to write a cp command that works properly.
+
+
+The "acp" command takes most of the standard flags, following the GNU
+conventions.  It adds a "-e" flag, used when copying executables around.
+On most systems it is ignored, but on MinGW/Cygwin it allows "cp foo bar"
+to work when what is actually meant is "cp foo.exe bar.exe".  Unlike the
+default Cygwin cp, "acp foo bar" will not find foo.exe unless you add
+the "-e" flag, avoiding potential ambiguity.
+
diff --git a/build/tools/acp/acp.c b/build/tools/acp/acp.c
new file mode 100644 (file)
index 0000000..eb1de1f
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2005 The Android Open Source Project
+ *
+ * Android "cp" replacement.
+ *
+ * The GNU/Linux "cp" uses O_LARGEFILE in its open() calls, utimes() instead
+ * of utime(), and getxattr()/setxattr() instead of chmod().  These are
+ * probably "better", but are non-portable, and not necessary for our
+ * purposes.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <utime.h>
+#include <limits.h>
+#include <errno.h>
+#include <assert.h>
+#include <host/CopyFile.h>
+
+/*#define DEBUG_MSGS*/
+#ifdef DEBUG_MSGS
+# define DBUG(x) printf x
+#else
+# define DBUG(x) ((void)0)
+#endif
+
+#define FSSEP '/'       /* filename separator char */
+
+
+/*
+ * Process the command-line file arguments.
+ *
+ * Returns 0 on success.
+ */
+int process(int argc, char* const argv[], unsigned int options)
+{
+    int retVal = 0;
+    int i, cc;
+    char* stripDest = NULL;
+    int stripDestLen;
+    struct stat destStat;
+    bool destMustBeDir = false;
+    struct stat sb;
+
+    assert(argc >= 2);
+
+    /*
+     * Check for and trim a trailing slash on the last arg.
+     *
+     * It's useful to be able to say "cp foo bar/" when you want to copy
+     * a single file into a directory.  If you say "cp foo bar", and "bar"
+     * does not exist, it will create "bar", when what you really wanted
+     * was for the cp command to fail with "directory does not exist".
+     */
+    stripDestLen = strlen(argv[argc-1]);
+    stripDest = malloc(stripDestLen+1);
+    memcpy(stripDest, argv[argc-1], stripDestLen+1);
+    if (stripDest[stripDestLen-1] == FSSEP) {
+        stripDest[--stripDestLen] = '\0';
+        destMustBeDir = true;
+    }
+
+    if (argc > 2)
+        destMustBeDir = true;
+
+    /*
+     * Start with a quick check to ensure that, if we're expecting to copy
+     * to a directory, the target already exists and is actually a directory.
+     * It's okay if it's a symlink to a directory.
+     *
+     * If it turns out to be a directory, go ahead and raise the
+     * destMustBeDir flag so we do some path concatenation below.
+     */
+    if (stat(stripDest, &sb) < 0) {
+        if (destMustBeDir) {
+            if (errno == ENOENT)
+                fprintf(stderr,
+                    "acp: destination directory '%s' does not exist\n",
+                    stripDest);
+            else
+                fprintf(stderr, "acp: unable to stat dest dir\n");
+            retVal = 1;
+            goto bail;
+        }
+    } else {
+        if (S_ISDIR(sb.st_mode)) {
+            DBUG(("--- dest exists and is a dir, setting flag\n"));
+            destMustBeDir = true;
+        } else if (destMustBeDir) {
+            fprintf(stderr,
+                "acp: destination '%s' is not a directory\n",
+                stripDest);
+            retVal = 1;
+            goto bail;
+        }
+    }
+
+    /*
+     * Copying files.
+     *
+     * Strip trailing slashes off.  They shouldn't be there, but
+     * sometimes file completion will put them in for directories.
+     *
+     * The observed behavior of GNU and BSD cp is that they print warnings
+     * if something fails, but continue on.  If any part fails, the command
+     * exits with an error status.
+     */
+    for (i = 0; i < argc-1; i++) {
+        const char* srcName;
+        char* src;
+        char* dst;
+        int copyResult;
+        int srcLen;
+
+        /* make a copy of the source name, and strip trailing '/' */
+        srcLen = strlen(argv[i]);
+        src = malloc(srcLen+1);
+        memcpy(src, argv[i], srcLen+1);
+
+        if (src[srcLen-1] == FSSEP)
+            src[--srcLen] = '\0';
+
+        /* find just the name part */
+        srcName = strrchr(src, FSSEP);
+        if (srcName == NULL) {
+            srcName = src;
+        } else {
+            srcName++;
+            assert(*srcName != '\0');
+        }
+        
+        if (destMustBeDir) {
+            /* concatenate dest dir and src name */
+            int srcNameLen = strlen(srcName);
+
+            dst = malloc(stripDestLen +1 + srcNameLen +1);
+            memcpy(dst, stripDest, stripDestLen);
+            dst[stripDestLen] = FSSEP;
+            memcpy(dst + stripDestLen+1, srcName, srcNameLen+1);
+        } else {
+            /* simple */
+            dst = stripDest;
+        }
+
+        /*
+         * Copy the source to the destination.
+         */
+        copyResult = copyFile(src, dst, options);
+
+        if (copyResult != 0)
+            retVal = 1;
+
+        free(src);
+        if (dst != stripDest)
+            free(dst);
+    }
+
+bail:
+    free(stripDest);
+    return retVal;
+}
+
+/*
+ * Set up the options.
+ */
+int main(int argc, char* const argv[])
+{
+    bool wantUsage;
+    int ic, retVal;
+    int verboseLevel;
+    unsigned int options;
+
+    verboseLevel = 0;
+    options = 0;
+    wantUsage = false;
+
+    while (1) {
+        ic = getopt(argc, argv, "defprtuv");
+        if (ic < 0)
+            break;
+
+        switch (ic) {
+            case 'd':
+                options |= COPY_NO_DEREFERENCE;
+                break;
+            case 'e':
+                options |= COPY_TRY_EXE;
+                break;
+            case 'f':
+                options |= COPY_FORCE;
+                break;
+            case 'p':
+                options |= COPY_PERMISSIONS;
+                break;
+            case 't':
+                options |= COPY_TIMESTAMPS;
+                break;
+            case 'r':
+                options |= COPY_RECURSIVE;
+                break;
+            case 'u':
+                options |= COPY_UPDATE_ONLY;
+                break;
+            case 'v':
+                verboseLevel++;
+                break;
+            default:
+                fprintf(stderr, "Unexpected arg -%c\n", ic);
+                wantUsage = true;
+                break;
+        }
+
+        if (wantUsage)
+            break;
+    }
+
+    options |= verboseLevel & COPY_VERBOSE_MASK;
+
+    if (optind == argc-1) {
+        fprintf(stderr, "acp: missing destination file\n");
+        return 2;
+    } else if (optind+2 > argc)
+        wantUsage = true;
+
+    if (wantUsage) {
+        fprintf(stderr, "Usage: acp [OPTION]... SOURCE DEST\n");
+        fprintf(stderr, "  or:  acp [OPTION]... SOURCE... DIRECTORY\n");
+        fprintf(stderr, "\nOptions:\n");
+        fprintf(stderr, "  -d  never follow (dereference) symbolic links\n");
+        fprintf(stderr, "  -e  if source file doesn't exist, try adding "
+                        "'.exe' [Win32 only]\n");
+        fprintf(stderr, "  -f  use force, removing existing file if it's "
+                        "not writeable\n");
+        fprintf(stderr, "  -p  preserve mode, ownership\n");
+        fprintf(stderr, "  -r  recursive copy\n");
+        fprintf(stderr, "  -t  preserve timestamps\n");
+        fprintf(stderr, "  -u  update only: don't copy if dest is newer\n");
+        fprintf(stderr, "  -v  verbose output (-vv is more verbose)\n");
+        return 2;
+    }
+
+    retVal = process(argc-optind, argv+optind, options);
+    DBUG(("EXIT: %d\n", retVal));
+    return retVal;
+}
+
diff --git a/build/tools/adbs b/build/tools/adbs
new file mode 100644 (file)
index 0000000..8277790
--- /dev/null
@@ -0,0 +1,223 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import re
+import string
+import sys
+
+###############################################################################
+# match "#00  pc 0003f52e  /system/lib/libdvm.so" for example
+###############################################################################
+trace_line = re.compile("(.*)(\#[0-9]+)  (..) ([0-9a-f]{8})  ([^\r\n \t]*)")
+
+# returns a list containing the function name and the file/lineno
+def CallAddr2Line(lib, addr):
+  global symbols_dir
+  global addr2line_cmd
+  global cppfilt_cmd
+
+  if lib != "":
+    cmd = addr2line_cmd + \
+        " -f -e " + symbols_dir + lib + " 0x" + addr
+    stream = os.popen(cmd)
+    lines = stream.readlines()
+    list = map(string.strip, lines)
+  else:
+    list = []
+  if list != []:
+    # Name like "move_forward_type<JavaVMOption>" causes troubles
+    mangled_name = re.sub('<', '\<', list[0]);
+    mangled_name = re.sub('>', '\>', mangled_name);
+    cmd = cppfilt_cmd + " " + mangled_name
+    stream = os.popen(cmd)
+    list[0] = stream.readline()
+    stream.close()
+    list = map(string.strip, list)
+  else:
+    list = [ "(unknown)", "(unknown)" ]
+  return list
+
+
+###############################################################################
+# similar to CallAddr2Line, but using objdump to find out the name of the
+# containing function of the specified address
+###############################################################################
+def CallObjdump(lib, addr):
+  global objdump_cmd
+  global symbols_dir
+
+  unknown = "(unknown)"
+  uname = os.uname()[0]
+  if uname == "Darwin":
+    proc = os.uname()[-1]
+    if proc == "i386":
+      uname = "darwin-x86"
+    else:
+      uname = "darwin-ppc"
+  elif uname == "Linux":
+    uname = "linux-x86"
+  if lib != "":
+    next_addr = string.atoi(addr, 16) + 1
+    cmd = objdump_cmd \
+        + " -C -d --start-address=0x" + addr + " --stop-address=" \
+        + str(next_addr) \
+        + " " + symbols_dir + lib
+    stream = os.popen(cmd)
+    lines = stream.readlines()
+    map(string.strip, lines)
+    stream.close()
+  else:
+    return unknown
+
+  # output looks like
+  #
+  # file format elf32-littlearm
+  #
+  # Disassembly of section .text:
+  #
+  # 0000833c <func+0x4>:
+  #        833c:       701a            strb    r2, [r3, #0]
+  #
+  # we want to extract the "func" part
+  num_lines = len(lines)
+  if num_lines < 2:
+    return unknown
+  func_name = lines[num_lines-2]
+  func_regexp = re.compile("(^.*\<)(.*)(\+.*\>:$)")
+  components = func_regexp.match(func_name)
+  if components is None:
+    return unknown
+  return components.group(2)
+
+###############################################################################
+# determine the symbols directory in the local build
+###############################################################################
+def FindSymbolsDir():
+  global symbols_dir
+
+  try:
+    path = os.environ['ANDROID_PRODUCT_OUT'] + "/symbols"
+  except:
+    cmd = "CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core " \
+      + "SRC_TARGET_DIR=build/target make -f build/core/envsetup.mk " \
+      + "dumpvar-abs-TARGET_OUT_UNSTRIPPED"
+    stream = os.popen(cmd)
+    str = stream.read()
+    stream.close()
+    path = str.strip()
+
+  if (not os.path.exists(path)):
+    print path + " not found!"
+    sys.exit(1)
+
+  symbols_dir = path
+
+###############################################################################
+# determine the path of binutils
+###############################################################################
+def SetupToolsPath():
+  global addr2line_cmd
+  global objdump_cmd
+  global cppfilt_cmd
+  global symbols_dir
+
+  uname = os.uname()[0]
+  if uname == "Darwin":
+    proc = os.uname()[-1]
+    if proc == "i386":
+      uname = "darwin-x86"
+    else:
+      uname = "darwin-ppc"
+  elif uname == "Linux":
+    uname = "linux-x86"
+  prefix = "./prebuilt/" + uname + "/toolchain/arm-eabi-4.4.3/bin/"
+  addr2line_cmd = prefix + "arm-eabi-addr2line"
+
+  if (not os.path.exists(addr2line_cmd)):
+    try:
+      prefix = os.environ['ANDROID_BUILD_TOP'] + "/prebuilt/" + uname + \
+               "/toolchain/arm-eabi-4.4.3/bin/"
+    except:
+      prefix = "";
+
+    addr2line_cmd = prefix + "arm-eabi-addr2line"
+    if (not os.path.exists(addr2line_cmd)):
+      print addr2line_cmd + " not found!"
+      sys.exit(1)
+
+  objdump_cmd = prefix + "arm-eabi-objdump"
+  cppfilt_cmd = prefix + "arm-eabi-c++filt"
+
+###############################################################################
+# look up the function and file/line number for a raw stack trace line
+# groups[0]: log tag
+# groups[1]: stack level
+# groups[2]: "pc"
+# groups[3]: code address
+# groups[4]: library name
+###############################################################################
+def SymbolTranslation(groups):
+  lib_name = groups[4]
+  code_addr = groups[3]
+  caller = CallObjdump(lib_name, code_addr)
+  func_line_pair = CallAddr2Line(lib_name, code_addr)
+
+  # If a callee is inlined to the caller, objdump will see the caller's
+  # address but addr2line will report the callee's address. So the printed
+  # format is desgined to be "caller<-callee  file:line"
+  if (func_line_pair[0] != caller):
+    print groups[0] + groups[1] + " " + caller + "<-" + \
+          '  '.join(func_line_pair[:]) + " "
+  else:
+    print groups[0] + groups[1] + " " + '  '.join(func_line_pair[:]) + " "
+
+###############################################################################
+
+if __name__ == '__main__':
+  # pass the options to adb
+  adb_cmd  = "adb " + ' '.join(sys.argv[1:])
+
+  # setup addr2line_cmd and objdump_cmd
+  SetupToolsPath()
+
+  # setup the symbols directory
+  FindSymbolsDir()
+
+  # invoke the adb command and filter its output
+  stream = os.popen(adb_cmd)
+  while (True):
+    line = stream.readline()
+
+    # EOF reached
+    if (line == ''):
+      break
+
+    # remove the trailing \n
+    line = line.strip()
+
+    # see if this is a stack trace line
+    match = trace_line.match(line)
+    if (match):
+      groups = match.groups()
+      # translate raw address into symbols
+      SymbolTranslation(groups)
+    else:
+      print line
+      sys.stdout.flush()
+
+  # adb itself aborts
+  stream.close()
diff --git a/build/tools/apicheck/Android.mk b/build/tools/apicheck/Android.mk
new file mode 100644 (file)
index 0000000..a2ff8a2
--- /dev/null
@@ -0,0 +1,44 @@
+# Copyright (C) 2007-2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+# We use copy-file-to-new-target so that the installed
+# script file's timestamp is at least as new as the
+# .jar file it wraps.
+
+#TODO(dbort): add a template to do this stuff; share with jx
+
+# the hat script
+# ============================================================
+include $(CLEAR_VARS)
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE := apicheck
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): $(HOST_OUT_JAVA_LIBRARIES)/apicheck$(COMMON_JAVA_PACKAGE_SUFFIX)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/apicheck | $(ACP)
+       @echo "Copy: $(PRIVATE_MODULE) ($@)"
+       $(copy-file-to-new-target)
+       $(hide) chmod 755 $@
+
+# the other stuff
+# ============================================================
+subdirs := $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
+               src \
+       ))
+
+include $(subdirs)
diff --git a/build/tools/apicheck/etc/apicheck b/build/tools/apicheck/etc/apicheck
new file mode 100644 (file)
index 0000000..5d0480c
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/bash
+#
+# Copyright (C) 2005, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Set up prog to be the path of this script, including following symlinks,
+# and set up progdir to be the fully-qualified pathname of its directory.
+prog="$0"
+while [ -h "${prog}" ]; do
+    newProg=`/bin/ls -ld "${prog}"`
+    newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
+    if expr "x${newProg}" : 'x/' >/dev/null; then
+        prog="${newProg}"
+    else
+        progdir=`dirname "${prog}"`
+        prog="${progdir}/${newProg}"
+    fi
+done
+oldwd=`pwd`
+progdir=`dirname "${prog}"`
+cd "${progdir}"
+progdir=`pwd`
+prog="${progdir}"/`basename "${prog}"`
+cd "${oldwd}"
+
+libdir=`dirname $progdir`/framework
+
+javaOpts=""
+while expr "x$1" : 'x-J' >/dev/null; do
+    opt=`expr "x$1" : 'x-J\(.*\)'`
+    javaOpts="${javaOpts} -${opt}"
+    shift
+done
+
+exec java $javaOpts -jar $libdir/apicheck.jar "$@"
diff --git a/build/tools/apicheck/src/Android.mk b/build/tools/apicheck/src/Android.mk
new file mode 100644 (file)
index 0000000..c4e7c6e
--- /dev/null
@@ -0,0 +1,28 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+
+# apicheck java library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_JAR_MANIFEST := MANIFEST.mf
+
+LOCAL_MODULE:= apicheck
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
diff --git a/build/tools/apicheck/src/MANIFEST.mf b/build/tools/apicheck/src/MANIFEST.mf
new file mode 100644 (file)
index 0000000..e6dc263
--- /dev/null
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+Main-Class: com.android.apicheck.ApiCheck
diff --git a/build/tools/apicheck/src/com/android/apicheck/AbstractMethodInfo.java b/build/tools/apicheck/src/com/android/apicheck/AbstractMethodInfo.java
new file mode 100644 (file)
index 0000000..ca90820
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.apicheck;
+
+public interface AbstractMethodInfo {
+  
+    public void addException(String exec);
+    public void addParameter(ParameterInfo p);
+
+}
diff --git a/build/tools/apicheck/src/com/android/apicheck/ApiCheck.java b/build/tools/apicheck/src/com/android/apicheck/ApiCheck.java
new file mode 100644 (file)
index 0000000..c8272dd
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.apicheck;
+
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Stack;
+
+public class ApiCheck {
+        // parse out and consume the -whatever command line flags
+        private static ArrayList<String[]> parseFlags(ArrayList<String> allArgs) {
+            ArrayList<String[]> ret = new ArrayList<String[]>();
+
+            int i;
+            for (i = 0; i < allArgs.size(); i++) {
+                // flags with one value attached
+                String flag = allArgs.get(i);
+                if (flag.equals("-error")
+                        || flag.equals("-warning")
+                        || flag.equals("-hide")) {
+                    String[] arg = new String[2];
+                    arg[0] = flag;
+                    arg[1] = allArgs.get(++i);
+                    ret.add(arg);
+                } else {
+                    // we've consumed all of the -whatever args, so we're done
+                    break;
+                }
+            }
+
+            // i now points to the first non-flag arg; strip what came before
+            for (; i > 0; i--) {
+                allArgs.remove(0);
+            }
+            return ret;
+        }
+
+        public static void main(String[] originalArgs) {
+            // translate to an ArrayList<String> for munging
+            ArrayList<String> args = new ArrayList<String>(originalArgs.length);
+            for (String a: originalArgs) {
+                args.add(a);
+            }
+
+            ArrayList<String[]> flags = ApiCheck.parseFlags(args);
+            for (String[] a: flags) {
+                if (a[0].equals("-error") || a[0].equals("-warning")
+                        || a[0].equals("-hide")) {
+                    try {
+                        int level = -1;
+                        if (a[0].equals("-error")) {
+                            level = Errors.ERROR;
+                        }
+                        else if (a[0].equals("-warning")) {
+                            level = Errors.WARNING;
+                        }
+                        else if (a[0].equals("-hide")) {
+                            level = Errors.HIDDEN;
+                        }
+                        Errors.setErrorLevel(Integer.parseInt(a[1]), level);
+                    }
+                    catch (NumberFormatException e) {
+                        System.err.println("Bad argument: " + a[0] + " " + a[1]);
+                        System.exit(2);
+                    }
+                }
+            }
+
+            ApiCheck acheck = new ApiCheck();
+
+            ApiInfo oldApi = acheck.parseApi(args.get(0));
+            ApiInfo newApi = acheck.parseApi(args.get(1));
+
+            // only run the consistency check if we haven't had XML parse errors
+            if (!Errors.hadError) {
+                oldApi.isConsistent(newApi);
+            }
+
+            Errors.printErrors();
+            System.exit(Errors.hadError ? 1 : 0);
+        }
+
+    public ApiInfo parseApi(String xmlFile) {
+        FileReader fileReader = null;
+        try {
+            XMLReader xmlreader = XMLReaderFactory.createXMLReader();
+            MakeHandler handler = new MakeHandler();
+            xmlreader.setContentHandler(handler);
+            xmlreader.setErrorHandler(handler);
+            fileReader = new FileReader(xmlFile);
+            xmlreader.parse(new InputSource(fileReader));
+            ApiInfo apiInfo = handler.getApi();
+            apiInfo.resolveSuperclasses();
+            return apiInfo;
+        } catch (SAXParseException e) {
+            Errors.error(Errors.PARSE_ERROR,
+                    new SourcePositionInfo(xmlFile, e.getLineNumber(), 0),
+                    e.getMessage());
+        } catch (Exception e) {
+            e.printStackTrace();
+            Errors.error(Errors.PARSE_ERROR,
+                    new SourcePositionInfo(xmlFile, 0, 0), e.getMessage());
+        } finally {
+            if (fileReader != null) {
+                try {
+                    fileReader.close();
+                } catch (IOException ignored) {}
+            }
+        }
+        return null;
+    }
+
+    private static class MakeHandler extends DefaultHandler {
+
+            private ApiInfo mApi;
+            private PackageInfo mCurrentPackage;
+            private ClassInfo mCurrentClass;
+            private AbstractMethodInfo mCurrentMethod;
+            private Stack<ClassInfo> mClassScope = new Stack<ClassInfo>();
+
+
+            public MakeHandler() {
+                super();
+                mApi = new ApiInfo();
+            }
+
+            @Override
+            public void startElement(String uri, String localName, String qName,
+                                     Attributes attributes) {
+                if (qName.equals("package")) {
+                    mCurrentPackage = new PackageInfo(attributes.getValue("name"),
+                            SourcePositionInfo.fromXml(attributes.getValue("source")));
+                } else if (qName.equals("class")
+                        || qName.equals("interface")) {
+                    // push the old outer scope for later recovery, then set
+                    // up the new current class object
+                    mClassScope.push(mCurrentClass);
+                    mCurrentClass = new ClassInfo(attributes.getValue("name"),
+                                                  mCurrentPackage,
+                                                  attributes.getValue("extends") ,
+                                                  qName.equals("interface"),
+                                                  Boolean.valueOf(
+                                                      attributes.getValue("abstract")),
+                                                  Boolean.valueOf(
+                                                      attributes.getValue("static")),
+                                                  Boolean.valueOf(
+                                                      attributes.getValue("final")),
+                                                  attributes.getValue("deprecated"),
+                                                  attributes.getValue("visibility"),
+                                                  SourcePositionInfo.fromXml(attributes.getValue("source")),
+                                                  mCurrentClass);
+                } else if (qName.equals("method")) {
+                    mCurrentMethod = new MethodInfo(attributes.getValue("name"),
+                                                    attributes.getValue("return") ,
+                                                    Boolean.valueOf(
+                                                        attributes.getValue("abstract")),
+                                                    Boolean.valueOf(
+                                                        attributes.getValue("native")),
+                                                    Boolean.valueOf(
+                                                        attributes.getValue("synchronized")),
+                                                    Boolean.valueOf(
+                                                        attributes.getValue("static")),
+                                                    Boolean.valueOf(
+                                                        attributes.getValue("final")),
+                                                    attributes.getValue("deprecated"),
+                                                    attributes.getValue("visibility"),
+                                                    SourcePositionInfo.fromXml(attributes.getValue("source")),
+                                                    mCurrentClass);
+                } else if (qName.equals("constructor")) {
+                    mCurrentMethod = new ConstructorInfo(attributes.getValue("name"),
+                                                         attributes.getValue("type") ,
+                                                         Boolean.valueOf(
+                                                             attributes.getValue("static")),
+                                                         Boolean.valueOf(
+                                                             attributes.getValue("final")),
+                                                         attributes.getValue("deprecated"),
+                                                         attributes.getValue("visibility"),
+                                                         SourcePositionInfo.fromXml(attributes.getValue("source")),
+                                                         mCurrentClass);
+                } else if (qName.equals("field")) {
+                    FieldInfo fInfo = new FieldInfo(attributes.getValue("name"),
+                                                    attributes.getValue("type") ,
+                                                    Boolean.valueOf(
+                                                        attributes.getValue("transient")),
+                                                    Boolean.valueOf(
+                                                        attributes.getValue("volatile")),
+                                                    attributes.getValue("value"),
+                                                    Boolean.valueOf(
+                                                        attributes.getValue("static")),
+                                                    Boolean.valueOf(
+                                                        attributes.getValue("final")),
+                                                    attributes.getValue("deprecated"),
+                                                    attributes.getValue("visibility"),
+                                                    SourcePositionInfo.fromXml(attributes.getValue("source")),
+                                                    mCurrentClass);
+                    mCurrentClass.addField(fInfo);
+                } else if (qName.equals("parameter")) {
+                    mCurrentMethod.addParameter(new ParameterInfo(attributes.getValue("type"),
+                                                                  attributes.getValue("name")));
+                } else if (qName.equals("exception")) {
+                    mCurrentMethod.addException(attributes.getValue("type"));
+                } else if (qName.equals("implements")) {
+                    mCurrentClass.addInterface(attributes.getValue("name"));
+                }
+            }
+
+            @Override
+            public void endElement(String uri, String localName, String qName) {
+                if (qName.equals("method")) {
+                    mCurrentClass.addMethod((MethodInfo) mCurrentMethod);
+                } else if (qName.equals("constructor")) {
+                    mCurrentClass.addConstructor((ConstructorInfo) mCurrentMethod);
+                } else if (qName.equals("class")
+                        || qName.equals("interface")) {
+                    mCurrentPackage.addClass(mCurrentClass);
+                    mCurrentClass = mClassScope.pop();
+                } else if (qName.equals("package")){
+                    mApi.addPackage(mCurrentPackage);
+                }
+            }
+            public ApiInfo getApi() {
+                return mApi;
+            }
+        }
+}
diff --git a/build/tools/apicheck/src/com/android/apicheck/ApiInfo.java b/build/tools/apicheck/src/com/android/apicheck/ApiInfo.java
new file mode 100644 (file)
index 0000000..c237814
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.apicheck;
+import java.util.*;
+
+public class ApiInfo {
+  
+    private HashMap<String, PackageInfo> mPackages;
+    private HashMap<String, ClassInfo> mAllClasses;
+    
+    public ApiInfo() {
+        mPackages = new HashMap<String, PackageInfo>();
+        mAllClasses = new HashMap<String, ClassInfo>();
+    }
+
+    public ClassInfo findClass(String name) {
+        return mAllClasses.get(name);
+    }
+
+    private void resolveInterfaces() {
+        for (ClassInfo c : mAllClasses.values()) {
+            c.resolveInterfaces(this);
+        }
+    }
+    
+    public boolean isConsistent(ApiInfo otherApi) {
+        resolveInterfaces();
+        boolean consistent = true;
+        for (PackageInfo pInfo : mPackages.values()) {
+            if (otherApi.getPackages().containsKey(pInfo.name())) {
+                if (!pInfo.isConsistent(otherApi.getPackages().get(pInfo.name()))) {
+                    consistent = false;
+                }
+            } else {
+                Errors.error(Errors.REMOVED_PACKAGE, pInfo.position(),
+                        "Removed package " + pInfo.name());
+                consistent = false;
+            }
+        }
+        for (PackageInfo pInfo : otherApi.mPackages.values()) {
+            if (!pInfo.isInBoth()) {
+                Errors.error(Errors.ADDED_PACKAGE, pInfo.position(),
+                        "Added package " + pInfo.name());
+                consistent = false;
+            }
+        }
+        return consistent;
+    }
+    
+    public HashMap<String, PackageInfo> getPackages() {
+        return mPackages;
+    }
+    
+    public void addPackage(PackageInfo pInfo) {
+        // track the set of organized packages in the API
+        mPackages.put(pInfo.name(), pInfo);
+        
+        // accumulate a direct map of all the classes in the API
+        for (ClassInfo cl: pInfo.allClasses().values()) {
+            mAllClasses.put(cl.qualifiedName(), cl);
+        }
+    }
+
+    public void resolveSuperclasses() {
+        for (ClassInfo cl: mAllClasses.values()) {
+            // java.lang.Object has no superclass
+            if (!cl.qualifiedName().equals("java.lang.Object")) {
+                String scName = cl.superclassName();
+                if (scName == null) {
+                    scName = "java.lang.Object";
+                }
+
+                ClassInfo superclass = mAllClasses.get(scName);
+                cl.setSuperClass(superclass);
+            }
+        }
+    }
+}
diff --git a/build/tools/apicheck/src/com/android/apicheck/ClassInfo.java b/build/tools/apicheck/src/com/android/apicheck/ClassInfo.java
new file mode 100644 (file)
index 0000000..e62a3d0
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.apicheck;
+import java.util.*;
+
+public class ClassInfo {
+    private String mName;
+    private String mSuperClassName;
+    private boolean mIsInterface;
+    private boolean mIsAbstract;
+    private boolean mIsStatic;
+    private boolean mIsFinal;
+    private String mDeprecated;
+    private String mScope;
+    private List<String> mInterfaceNames;
+    private List<ClassInfo> mInterfaces;
+    private HashMap<String, MethodInfo> mMethods;
+    private HashMap<String, FieldInfo> mFields;
+    private HashMap<String, ConstructorInfo> mConstructors;
+    private boolean mExistsInBoth;
+    private PackageInfo mPackage;
+    private SourcePositionInfo mSourcePosition;
+    private ClassInfo mSuperClass;
+    private ClassInfo mParentClass;
+
+    public ClassInfo(String name, PackageInfo pack, String superClass, boolean isInterface,
+                     boolean isAbstract, boolean isStatic, boolean isFinal, String deprecated,
+                     String visibility, SourcePositionInfo source, ClassInfo parent) {
+        mName = name;
+        mPackage = pack;
+        mSuperClassName = superClass;
+        mIsInterface = isInterface;
+        mIsAbstract = isAbstract;
+        mIsStatic = isStatic;
+        mIsFinal = isFinal;
+        mDeprecated = deprecated;
+        mScope = visibility;
+        mInterfaceNames = new ArrayList<String>();
+        mInterfaces = new ArrayList<ClassInfo>();
+        mMethods = new HashMap<String, MethodInfo>();
+        mFields = new HashMap<String, FieldInfo>();
+        mConstructors = new HashMap<String, ConstructorInfo>();
+        mExistsInBoth = false;
+        mSourcePosition = source;
+        mParentClass = parent;
+    }
+
+    public String name() {
+        return mName;
+    }
+
+    public String qualifiedName() {
+        String parentQName = (mParentClass != null)
+                ? (mParentClass.qualifiedName() + ".")
+                : "";
+        return mPackage.name() + "." + parentQName + name();
+    }
+
+    public String superclassName() {
+        return mSuperClassName;
+    }
+    
+    public SourcePositionInfo position() {
+        return mSourcePosition;
+    }
+
+    public boolean isInterface() {
+        return mIsInterface;
+    }
+
+    public boolean isFinal() {
+        return mIsFinal;
+    }
+    
+    // Find a superclass implementation of the given method.  Looking at our superclass
+    // instead of at 'this' is unusual, but it fits the point-of-call demands well.
+    public MethodInfo overriddenMethod(MethodInfo candidate) {
+        if (mSuperClass == null) {
+            return null;
+        }
+        
+        // does our immediate superclass have it?
+        ClassInfo sup = mSuperClass;
+        for (MethodInfo mi : sup.mMethods.values()) {
+            if (mi.matches(candidate)) {
+                // found it
+                return mi;
+            }
+        }
+
+        // no, so recurse
+        if (sup.mSuperClass != null) {
+            return mSuperClass.overriddenMethod(candidate);
+        }
+        
+        // no parent, so we just don't have it
+        return null;
+    }
+    
+    // Find a superinterface declaration of the given method.
+    public MethodInfo interfaceMethod(MethodInfo candidate) {
+        for (ClassInfo interfaceInfo : mInterfaces) {
+            for (MethodInfo mi : interfaceInfo.mMethods.values()) {
+                if (mi.matches(candidate)) {
+                    return mi;
+                }
+            }
+        }
+        return (mSuperClass != null) ? mSuperClass.interfaceMethod(candidate) : null;
+    }
+
+    public boolean isConsistent(ClassInfo cl) {
+        cl.mExistsInBoth = true;
+        mExistsInBoth = true;
+        boolean consistent = true;
+
+        if (isInterface() != cl.isInterface()) {
+            Errors.error(Errors.CHANGED_CLASS, cl.position(),
+                    "Class " + cl.qualifiedName()
+                    + " changed class/interface declaration");
+            consistent = false;
+        }
+        for (String iface : mInterfaceNames) {
+            boolean found = false;
+            for (ClassInfo c = cl; c != null && !found; c = c.mSuperClass) {
+                found = c.mInterfaceNames.contains(iface);
+            }
+            if (!found) {
+                Errors.error(Errors.REMOVED_INTERFACE, cl.position(),
+                        "Class " + qualifiedName() + " no longer implements " + iface);
+            }
+        }
+        for (String iface : cl.mInterfaceNames) {
+          if (!mInterfaceNames.contains(iface)) {
+              Errors.error(Errors.ADDED_INTERFACE, cl.position(),
+                      "Added interface " + iface + " to class "
+                      + qualifiedName());
+              consistent = false;
+            }
+        }
+        
+        for (MethodInfo mInfo : mMethods.values()) {
+            if (cl.mMethods.containsKey(mInfo.getHashableName())) {
+                if (!mInfo.isConsistent(cl.mMethods.get(mInfo.getHashableName()))) {
+                    consistent = false;
+                }
+            } else {
+                /* This class formerly provided this method directly, and now does not.
+                 * Check our ancestry to see if there's an inherited version that still
+                 * fulfills the API requirement.
+                 */
+                MethodInfo mi = mInfo.containingClass().overriddenMethod(mInfo);
+                if (mi == null) {
+                    mi = mInfo.containingClass().interfaceMethod(mInfo);
+                }
+                if (mi == null) {
+                    Errors.error(Errors.REMOVED_METHOD, mInfo.position(),
+                            "Removed public method " + mInfo.qualifiedName());
+                    consistent = false;
+                }
+            }
+        }
+        for (MethodInfo mInfo : cl.mMethods.values()) {
+            if (!mInfo.isInBoth()) {
+                /* Similarly to the above, do not fail if this "new" method is
+                 * really an override of an existing superclass method.
+                 */
+                MethodInfo mi = mInfo.containingClass().overriddenMethod(mInfo);
+                if (mi == null) {
+                    Errors.error(Errors.ADDED_METHOD, mInfo.position(),
+                            "Added public method " + mInfo.qualifiedName());
+                    consistent = false;
+                }
+            }
+        }
+        
+        for (ConstructorInfo mInfo : mConstructors.values()) {
+          if (cl.mConstructors.containsKey(mInfo.getHashableName())) {
+              if (!mInfo.isConsistent(cl.mConstructors.get(mInfo.getHashableName()))) {
+                  consistent = false;
+              }
+          } else {
+              Errors.error(Errors.REMOVED_METHOD, mInfo.position(),
+                      "Removed public constructor " + mInfo.prettySignature());
+              consistent = false;
+          }
+        }
+        for (ConstructorInfo mInfo : cl.mConstructors.values()) {
+            if (!mInfo.isInBoth()) {
+                Errors.error(Errors.ADDED_METHOD, mInfo.position(),
+                        "Added public constructor " + mInfo.prettySignature());
+                consistent = false;
+            }
+        }
+        
+        for (FieldInfo mInfo : mFields.values()) {
+          if (cl.mFields.containsKey(mInfo.name())) {
+              if (!mInfo.isConsistent(cl.mFields.get(mInfo.name()))) {
+                  consistent = false;
+              }
+          } else {
+              Errors.error(Errors.REMOVED_FIELD, mInfo.position(),
+                      "Removed field " + mInfo.qualifiedName());
+              consistent = false;
+          }
+        }
+        for (FieldInfo mInfo : cl.mFields.values()) {
+            if (!mInfo.isInBoth()) {
+                Errors.error(Errors.ADDED_FIELD, mInfo.position(),
+                        "Added public field " + mInfo.qualifiedName());
+                consistent = false;
+            }
+        }
+        
+        if (mIsAbstract != cl.mIsAbstract) {
+            consistent = false;
+            Errors.error(Errors.CHANGED_ABSTRACT, cl.position(),
+                    "Class " + cl.qualifiedName() + " changed abstract qualifier");
+        }
+      
+        if (mIsFinal != cl.mIsFinal) {
+            consistent = false;
+            Errors.error(Errors.CHANGED_FINAL, cl.position(),
+                    "Class " + cl.qualifiedName() + " changed final qualifier");
+        }
+      
+        if (mIsStatic != cl.mIsStatic) {
+            consistent = false;
+            Errors.error(Errors.CHANGED_STATIC, cl.position(),
+                    "Class " + cl.qualifiedName() + " changed static qualifier");
+        }
+     
+        if (!mScope.equals(cl.mScope)) {
+            consistent = false;
+            Errors.error(Errors.CHANGED_SCOPE, cl.position(),
+                    "Class " + cl.qualifiedName() + " scope changed from "
+                    + mScope + " to " + cl.mScope);
+        }
+        
+        if (!mDeprecated.equals(cl.mDeprecated)) {
+            consistent = false;
+            Errors.error(Errors.CHANGED_DEPRECATED, cl.position(),
+                    "Class " + cl.qualifiedName() + " has changed deprecation state");
+        }
+        
+        if (mSuperClassName != null) {
+            if (cl.mSuperClassName == null || !mSuperClassName.equals(cl.mSuperClassName)) {
+                consistent = false;
+                Errors.error(Errors.CHANGED_SUPERCLASS, cl.position(),
+                        "Class " + qualifiedName() + " superclass changed from "
+                        + mSuperClassName + " to " + cl.mSuperClassName);
+            }
+        } else if (cl.mSuperClassName != null) {
+            consistent = false;
+            Errors.error(Errors.CHANGED_SUPERCLASS, cl.position(),
+                    "Class " + qualifiedName() + " superclass changed from "
+                    + "null to " + cl.mSuperClassName);
+        }
+        
+        return consistent;
+    }
+
+    public void resolveInterfaces(ApiInfo apiInfo) {
+        for (String interfaceName : mInterfaceNames) {
+            mInterfaces.add(apiInfo.findClass(interfaceName));
+        }
+    }
+    
+    public void addInterface(String name) {
+        mInterfaceNames.add(name);
+    }
+    
+    public void addMethod(MethodInfo mInfo) {
+        mMethods.put(mInfo.getHashableName(), mInfo);
+    }
+    
+    public void addConstructor(ConstructorInfo cInfo) {
+        mConstructors.put(cInfo.getHashableName(), cInfo);
+        
+    }
+    
+    public void addField(FieldInfo fInfo) {
+        mFields.put(fInfo.name(), fInfo);
+      
+    }
+    
+    public void setSuperClass(ClassInfo superclass) {
+        mSuperClass = superclass;
+    }
+    
+    public boolean isInBoth() {
+        return mExistsInBoth;
+    }
+
+    public Map<String, ConstructorInfo> allConstructors() {
+        return mConstructors;
+    }
+
+    public Map<String, FieldInfo> allFields() {
+        return mFields;
+    }
+
+    public Map<String, MethodInfo> allMethods() {
+        return mMethods;
+    }
+
+    /**
+     * Returns the class hierarchy for this class, starting with this class.
+     */
+    public Iterable<ClassInfo> hierarchy() {
+        List<ClassInfo> result = new ArrayList<ClassInfo>(4);
+        for (ClassInfo c  = this; c != null; c = c.mSuperClass) {
+            result.add(c);
+        }
+        return result;
+    }
+}
diff --git a/build/tools/apicheck/src/com/android/apicheck/ConstructorInfo.java b/build/tools/apicheck/src/com/android/apicheck/ConstructorInfo.java
new file mode 100644 (file)
index 0000000..f36c7cd
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.apicheck;
+import java.util.*;
+
+public class ConstructorInfo implements AbstractMethodInfo {
+    
+    private String mName;
+    private String mType;
+    private boolean mIsStatic;
+    private boolean mIsFinal;
+    private String mDeprecated;
+    private String mScope;
+    private List<String> mExceptions;
+    private List<ParameterInfo> mParameters;
+    private boolean mExistsInBoth;
+    private SourcePositionInfo mSourcePosition;
+    private ClassInfo mClass;
+    
+    public ConstructorInfo(String name, String type, boolean isStatic, boolean isFinal,
+                           String deprecated, String scope, SourcePositionInfo pos, ClassInfo clazz) {
+        mName = name;
+        mType = type;
+        mIsStatic = isStatic;
+        mIsFinal = isFinal;
+        mDeprecated= deprecated;
+        mScope = scope;
+        mExistsInBoth = false;
+        mExceptions = new ArrayList<String>();
+        mParameters = new ArrayList<ParameterInfo>();
+        mSourcePosition = pos;
+        mClass = clazz;
+    }
+    
+    public void addParameter(ParameterInfo pInfo) {
+        mParameters.add(pInfo);
+    }
+    
+    public void addException(String exec) {
+        mExceptions.add(exec);
+    }
+    
+    public String getHashableName() {
+      StringBuilder result = new StringBuilder();
+      result.append(name());
+      for (ParameterInfo pInfo : mParameters) {
+          result.append(":").append(pInfo.getType());
+      }
+      return result.toString();
+    }
+    
+    public boolean isInBoth() {
+        return mExistsInBoth;
+    }
+    
+    public SourcePositionInfo position() {
+        return mSourcePosition;
+    }
+    
+    public String name() {
+        return mName;
+    }
+    
+    public String qualifiedName() {
+        String baseName = (mClass != null)
+                ? (mClass.qualifiedName() + ".")
+                : "";
+        return baseName + name();
+    }
+    
+    public String prettySignature() {
+        String params = "";
+        for (ParameterInfo pInfo : mParameters) {
+            if (params.length() > 0) {
+                params += ", ";
+            }
+            params += pInfo.getType();
+        }
+        return qualifiedName() + '(' + params + ')';
+    }
+    
+    public boolean isConsistent(ConstructorInfo mInfo) {
+      mInfo.mExistsInBoth = true;
+      mExistsInBoth = true;
+      boolean consistent = true;
+      
+      if (mIsFinal != mInfo.mIsFinal) {
+          consistent = false;
+          Errors.error(Errors.CHANGED_FINAL, mInfo.position(),
+                  "Constructor " + mInfo.qualifiedName() + " has changed 'final' qualifier");
+      }
+      
+      if (mIsStatic != mInfo.mIsStatic) {
+          consistent = false;
+          Errors.error(Errors.CHANGED_FINAL, mInfo.position(),
+                  "Constructor " + mInfo.qualifiedName() + " has changed 'static' qualifier");
+      }
+     
+      if (!mScope.equals(mInfo.mScope)) {
+          consistent = false;
+          Errors.error(Errors.CHANGED_SCOPE, mInfo.position(),
+                  "Constructor " + mInfo.qualifiedName() + " changed scope from "
+                  + mScope + " to " + mInfo.mScope);
+      }
+      
+      if (!mDeprecated.equals(mInfo.mDeprecated)) {
+          consistent = false;
+          Errors.error(Errors.CHANGED_DEPRECATED, mInfo.position(),
+                  "Constructor " + mInfo.qualifiedName() + " has changed deprecation state");
+      }
+      
+      for (String exec : mExceptions) {
+          if (!mInfo.mExceptions.contains(exec)) {
+              Errors.error(Errors.CHANGED_THROWS, mInfo.position(),
+                      "Constructor " + mInfo.qualifiedName() + " no longer throws exception "
+                      + exec);
+              consistent = false;
+          }
+      }
+      
+      for (String exec : mInfo.mExceptions) {
+          if (!mExceptions.contains(exec)) {
+              Errors.error(Errors.CHANGED_THROWS, mInfo.position(),
+                      "Constructor " + mInfo.qualifiedName() + " added thrown exception "
+                      + exec);
+            consistent = false;
+          }
+      }
+      
+      return consistent;
+  }
+    
+
+}
diff --git a/build/tools/apicheck/src/com/android/apicheck/Errors.java b/build/tools/apicheck/src/com/android/apicheck/Errors.java
new file mode 100644 (file)
index 0000000..b0b620e
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.apicheck;
+
+import java.lang.Comparable;
+import java.util.TreeSet;
+
+public class Errors
+{
+    public static boolean hadError = false;
+    private static boolean warningsAreErrors = false;
+    private static TreeSet<Message> allErrors = new TreeSet<Message>();
+
+    private static class Message implements Comparable {
+        SourcePositionInfo pos;
+        String msg;
+
+        Message(SourcePositionInfo p, String m) {
+            pos = p;
+            msg = m;
+        }
+
+        public int compareTo(Object o) {
+            Message that = (Message)o;
+            int r = this.pos.compareTo(that.pos);
+            if (r != 0) return r;
+            return this.msg.compareTo(that.msg);
+        }
+
+        @Override
+        public String toString() {
+            return this.pos.toString() + this.msg;
+        }
+    }
+
+    public static void error(Error error, SourcePositionInfo where, String text) {
+        if (error.level == HIDDEN) {
+            return;
+        }
+
+        String which = (!warningsAreErrors && error.level == WARNING) ? " warning " : " error ";
+        String message = which + error.code + ": " + text;
+
+        if (where == null) {
+            where = new SourcePositionInfo("unknown", 0, 0);
+        }
+
+        allErrors.add(new Message(where, message));
+
+        if (error.level == ERROR || (warningsAreErrors && error.level == WARNING)) {
+            hadError = true;
+        }
+    }
+
+    public static void printErrors() {
+        for (Message m: allErrors) {
+            System.err.println(m.toString());
+        }
+    }
+
+    public static int HIDDEN = 0;
+    public static int WARNING = 1;
+    public static int ERROR = 2;
+
+    public static void setWarningsAreErrors(boolean val) {
+        warningsAreErrors = val;
+    }
+
+    public static class Error {
+        public int code;
+        public int level;
+
+        public Error(int code, int level)
+        {
+            this.code = code;
+            this.level = level;
+        }
+    }
+
+    public static Error PARSE_ERROR = new Error(1, ERROR);
+    public static Error ADDED_PACKAGE = new Error(2, WARNING);
+    public static Error ADDED_CLASS = new Error(3, WARNING);
+    public static Error ADDED_METHOD = new Error(4, WARNING);
+    public static Error ADDED_FIELD = new Error(5, WARNING);
+    public static Error ADDED_INTERFACE = new Error(6, WARNING);
+    public static Error REMOVED_PACKAGE = new Error(7, WARNING);
+    public static Error REMOVED_CLASS = new Error(8, WARNING);
+    public static Error REMOVED_METHOD = new Error(9, WARNING);
+    public static Error REMOVED_FIELD = new Error(10, WARNING);
+    public static Error REMOVED_INTERFACE = new Error(11, WARNING);
+    public static Error CHANGED_STATIC = new Error(12, WARNING);
+    public static Error CHANGED_FINAL = new Error(13, WARNING);
+    public static Error CHANGED_TRANSIENT = new Error(14, WARNING);
+    public static Error CHANGED_VOLATILE = new Error(15, WARNING);
+    public static Error CHANGED_TYPE = new Error(16, WARNING);
+    public static Error CHANGED_VALUE = new Error(17, WARNING);
+    public static Error CHANGED_SUPERCLASS = new Error(18, WARNING);
+    public static Error CHANGED_SCOPE = new Error(19, WARNING);
+    public static Error CHANGED_ABSTRACT = new Error(20, WARNING);
+    public static Error CHANGED_THROWS = new Error(21, WARNING);
+    public static Error CHANGED_NATIVE = new Error(22, HIDDEN);
+    public static Error CHANGED_CLASS = new Error(23, WARNING);
+    public static Error CHANGED_DEPRECATED = new Error(24, WARNING);
+    public static Error CHANGED_SYNCHRONIZED = new Error(25, ERROR);
+
+    public static Error[] ERRORS = {
+        PARSE_ERROR,
+        ADDED_PACKAGE,
+        ADDED_CLASS,
+        ADDED_METHOD,
+        ADDED_FIELD,
+        ADDED_INTERFACE,
+        REMOVED_PACKAGE,
+        REMOVED_CLASS,
+        REMOVED_METHOD,
+        REMOVED_FIELD,
+        REMOVED_INTERFACE,
+        CHANGED_STATIC,
+        CHANGED_FINAL,
+        CHANGED_TRANSIENT,
+        CHANGED_VOLATILE,
+        CHANGED_TYPE,
+        CHANGED_VALUE,
+        CHANGED_SUPERCLASS,
+        CHANGED_SCOPE,
+        CHANGED_ABSTRACT,
+        CHANGED_THROWS,
+        CHANGED_NATIVE,
+        CHANGED_CLASS,
+        CHANGED_DEPRECATED,
+        CHANGED_SYNCHRONIZED,
+        };
+
+    public static boolean setErrorLevel(int code, int level) {
+        for (Error e: ERRORS) {
+            if (e.code == code) {
+                e.level = level;
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/build/tools/apicheck/src/com/android/apicheck/FieldInfo.java b/build/tools/apicheck/src/com/android/apicheck/FieldInfo.java
new file mode 100644 (file)
index 0000000..d80d9f6
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.apicheck;
+
+public class FieldInfo {
+  
+    private String mName;
+    private String mType;
+    private boolean mIsTransient;
+    private boolean mIsVolatile;
+    private String mValue;
+    private boolean mIsStatic;
+    private boolean mIsFinal;
+    private String mDeprecated;
+    private String mScope;
+    private boolean mExistsInBoth;
+    private SourcePositionInfo mSourcePosition;
+    private ClassInfo mClass;
+    
+    public FieldInfo (String name, String type, boolean isTransient, boolean isVolatile,
+                       String value, boolean isStatic, boolean isFinal, String deprecated,
+                       String scope, SourcePositionInfo source, ClassInfo parent) {
+        mName = name;
+        mType = type;
+        mIsTransient = isTransient;
+        mIsVolatile = isVolatile;
+        mValue = value;
+        mIsStatic = isStatic;
+        mIsFinal = isFinal;
+        mDeprecated = deprecated;
+        mScope = scope;
+        mExistsInBoth = false;
+        mSourcePosition = source;
+        mClass = parent;
+    }
+    
+    public boolean isInBoth() {
+        return mExistsInBoth;
+    }
+    public SourcePositionInfo position() {
+        return mSourcePosition;
+    }
+    
+    public String name() {
+        return mName;
+    }
+    
+    public String qualifiedName() {
+        String parentQName = (mClass != null)
+                ? (mClass.qualifiedName() + ".")
+                : "";
+        return parentQName + name();
+    }
+    
+    // Check the declared value with a typed comparison, not a string comparison,
+    // to accommodate toolchains with different fp -> string conversions.
+    public boolean valueEquals(FieldInfo other) {
+        // Type mismatch means nonequal, as does a null/non-null mismatch
+        if (!mType.equals(other.mType)
+                || ((mValue == null) != (other.mValue == null))) {
+            return false;
+        }
+
+        // Null values are considered equal
+        if (mValue == null) {
+            return true;
+        }
+
+        // Floating point gets an implementation-type comparison; all others just use the string
+        // If float/double parse fails, fall back to string comparison -- it means that it's a
+        // canonical droiddoc-generated constant expression that represents a NaN.
+        try {
+            if (mType.equals("float")) {
+                float val = Float.parseFloat(mValue);
+                float otherVal = Float.parseFloat(other.mValue);
+                return (val == otherVal);
+            } else if (mType.equals("double")) {
+                double val = Double.parseDouble(mValue);
+                double otherVal = Double.parseDouble(other.mValue);
+                return (val == otherVal);
+            }
+        } catch (NumberFormatException e) {
+            // fall through
+        }
+        
+        return mValue.equals(other.mValue);
+    }
+
+    public boolean isConsistent(FieldInfo fInfo) {
+      fInfo.mExistsInBoth = true;
+      mExistsInBoth = true;
+      boolean consistent = true;
+      if (!mType.equals(fInfo.mType)) {
+          Errors.error(Errors.CHANGED_TYPE, fInfo.position(),
+                  "Field " + fInfo.qualifiedName() + " has changed type");
+          consistent = false;
+      }
+
+      if (!this.valueEquals(fInfo)) {
+          Errors.error(Errors.CHANGED_VALUE, fInfo.position(),
+                  "Field " + fInfo.qualifiedName() + " has changed value from "
+                  + mValue + " to " + fInfo.mValue);
+          consistent = false;
+      }
+      
+      if (!mScope.equals(fInfo.mScope)) {
+          Errors.error(Errors.CHANGED_SCOPE, fInfo.position(),
+                  "Method " + fInfo.qualifiedName() + " changed scope from "
+                  + mScope + " to " + fInfo.mScope);
+          consistent = false;
+      }
+      
+      if (mIsStatic != fInfo.mIsStatic) {
+          Errors.error(Errors.CHANGED_STATIC, fInfo.position(),
+                  "Field " + fInfo.qualifiedName() + " has changed 'static' qualifier");
+          consistent = false;
+      }
+      
+      if (mIsFinal != fInfo.mIsFinal) {
+          Errors.error(Errors.CHANGED_FINAL, fInfo.position(),
+                  "Field " + fInfo.qualifiedName() + " has changed 'final' qualifier");
+          consistent = false;
+      }
+      
+      if (mIsTransient != fInfo.mIsTransient) {
+          Errors.error(Errors.CHANGED_TRANSIENT, fInfo.position(),
+                  "Field " + fInfo.qualifiedName() + " has changed 'transient' qualifier");
+          consistent = false;
+      }
+      
+      if (mIsVolatile != fInfo.mIsVolatile) {
+          Errors.error(Errors.CHANGED_VOLATILE, fInfo.position(),
+                  "Field " + fInfo.qualifiedName() + " has changed 'volatile' qualifier");
+          consistent = false;
+      }
+      
+      if (!mDeprecated.equals(fInfo.mDeprecated)) {
+          Errors.error(Errors.CHANGED_DEPRECATED, fInfo.position(),
+                  "Field " + fInfo.qualifiedName() + " has changed deprecation state");
+          consistent = false;
+      }
+      
+      return consistent;
+    }
+
+}
diff --git a/build/tools/apicheck/src/com/android/apicheck/MethodInfo.java b/build/tools/apicheck/src/com/android/apicheck/MethodInfo.java
new file mode 100644 (file)
index 0000000..e4e4537
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.apicheck;
+import java.util.*;
+
+public class MethodInfo implements AbstractMethodInfo {
+  
+    private String mName;
+    private String mReturn;
+    private boolean mIsAbstract;
+    private boolean mIsNative;
+    private boolean mIsSynchronized;
+    private boolean mIsStatic;
+    private boolean mIsFinal;
+    private String mDeprecated;
+    private String mScope;
+    private boolean mExistsInBoth;
+    private List<ParameterInfo> mParameters;
+    private List<String> mExceptions;
+    private SourcePositionInfo mSourcePosition;
+    private ClassInfo mClass;
+    
+    public MethodInfo (String name, String returnType, boolean isAbstract, boolean isNative,
+                        boolean isSynchronized, boolean isStatic, boolean isFinal, String deprecated
+                        , String scope, SourcePositionInfo source, ClassInfo parent) {
+        
+        mName = name;
+        mReturn = returnType;
+        mIsAbstract = isAbstract;
+        mIsNative = isNative;
+        mIsSynchronized = isSynchronized;
+        mIsStatic = isStatic;
+        mIsFinal = isFinal;
+        mDeprecated = deprecated;
+        mScope = scope;
+        mParameters = new ArrayList<ParameterInfo>();
+        mExceptions = new ArrayList<String>();
+        mExistsInBoth = false;
+        mSourcePosition = source;
+        mClass = parent;
+    }
+    
+    
+    public String name() {
+        return mName;
+    }
+    
+    public String qualifiedName() {
+        String parentQName = (mClass != null)
+                ? (mClass.qualifiedName() + ".")
+                : "";
+        return parentQName + name();
+    }
+    
+    public String prettySignature() {
+        String params = "";
+        for (ParameterInfo pInfo : mParameters) {
+            if (params.length() > 0) {
+                params += ", ";
+            }
+            params += pInfo.getType();
+        }
+        return qualifiedName() + '(' + params + ')';
+    }
+    
+    public SourcePositionInfo position() {
+        return mSourcePosition;
+    }
+    
+    public ClassInfo containingClass() {
+        return mClass;
+    }
+
+    public boolean matches(MethodInfo other) {
+        return getSignature().equals(other.getSignature());
+    }
+    
+    public boolean isConsistent(MethodInfo mInfo) {
+        mInfo.mExistsInBoth = true;
+        mExistsInBoth = true;
+        boolean consistent = true;
+        if (!mReturn.equals(mInfo.mReturn)) {
+            consistent = false;
+            Errors.error(Errors.CHANGED_TYPE, mInfo.position(),
+                    "Method " + mInfo.qualifiedName() + " has changed return type from "
+                    + mReturn + " to " + mInfo.mReturn);
+        }
+        
+        if (mIsAbstract != mInfo.mIsAbstract) {
+            consistent = false;
+            Errors.error(Errors.CHANGED_ABSTRACT, mInfo.position(),
+                    "Method " + mInfo.qualifiedName() + " has changed 'abstract' qualifier");
+        }
+        
+        if (mIsNative != mInfo.mIsNative) {
+            consistent = false;
+            Errors.error(Errors.CHANGED_NATIVE, mInfo.position(),
+                    "Method " + mInfo.qualifiedName() + " has changed 'native' qualifier");
+        }
+        
+        if (mIsFinal != mInfo.mIsFinal) {
+            // Compiler-generated methods vary in their 'final' qual between versions of
+            // the compiler, so this check needs to be quite narrow.  A change in 'final'
+            // status of a method is only relevant if (a) the method is not declared 'static'
+            // and (b) the method's class is not itself 'final'.
+            if (!mIsStatic) {
+                if ((mClass == null) || (!mClass.isFinal())) {
+                    consistent = false;
+                    Errors.error(Errors.CHANGED_FINAL, mInfo.position(),
+                            "Method " + mInfo.qualifiedName() + " has changed 'final' qualifier");
+                }
+            }
+        }
+        
+        if (mIsStatic != mInfo.mIsStatic) {
+            consistent = false;
+            Errors.error(Errors.CHANGED_STATIC, mInfo.position(),
+                    "Method " + mInfo.qualifiedName() + " has changed 'static' qualifier");
+        }
+       
+        if (!mScope.equals(mInfo.mScope)) {
+            consistent = false;
+            Errors.error(Errors.CHANGED_SCOPE, mInfo.position(),
+                    "Method " + mInfo.qualifiedName() + " changed scope from "
+                    + mScope + " to " + mInfo.mScope);
+        }
+        
+        if (!mDeprecated.equals(mInfo.mDeprecated)) {
+            Errors.error(Errors.CHANGED_DEPRECATED, mInfo.position(),
+                    "Method " + mInfo.qualifiedName() + " has changed deprecation state");
+            consistent = false;
+        }
+        
+        if (mIsSynchronized != mInfo.mIsSynchronized) {
+            Errors.error(Errors.CHANGED_SYNCHRONIZED, mInfo.position(),
+                    "Method " + mInfo.qualifiedName() + " has changed 'synchronized' qualifier from " + mIsSynchronized + " to " + mInfo.mIsSynchronized);
+            consistent = false;
+        }
+        
+        for (String exec : mExceptions) {
+            if (!mInfo.mExceptions.contains(exec)) {
+                // exclude 'throws' changes to finalize() overrides with no arguments
+                if (!name().equals("finalize") || (mParameters.size() > 0)) {
+                    Errors.error(Errors.CHANGED_THROWS, mInfo.position(),
+                            "Method " + mInfo.qualifiedName() + " no longer throws exception "
+                            + exec);
+                    consistent = false;
+                }
+            }
+        }
+        
+        for (String exec : mInfo.mExceptions) {
+            // exclude 'throws' changes to finalize() overrides with no arguments
+            if (!mExceptions.contains(exec)) {
+                if (!name().equals("finalize") || (mParameters.size() > 0)) {
+                    Errors.error(Errors.CHANGED_THROWS, mInfo.position(),
+                            "Method " + mInfo.qualifiedName() + " added thrown exception "
+                            + exec);
+                    consistent = false;
+                }
+            }
+        }
+        
+        return consistent;
+    }
+    
+    public void addParameter(ParameterInfo pInfo) {
+        mParameters.add(pInfo);
+    }
+    
+    public void addException(String exc) {
+        mExceptions.add(exc);
+    }
+    
+    public String getParameterHash() {
+        String hash = "";
+        for (ParameterInfo pInfo : mParameters) {
+            hash += ":" + pInfo.getType();
+        }
+        return hash;
+    }
+    
+    public String getHashableName() {
+        return name() + getParameterHash();
+    }
+    
+    public String getSignature() {
+        return name() + getParameterHash();
+    }
+    
+    public boolean isInBoth() {
+        return mExistsInBoth;
+    }
+
+}
diff --git a/build/tools/apicheck/src/com/android/apicheck/PackageInfo.java b/build/tools/apicheck/src/com/android/apicheck/PackageInfo.java
new file mode 100644 (file)
index 0000000..2262f21
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.apicheck;
+import java.util.*;
+
+public class PackageInfo {
+    private String mName;
+    private HashMap<String, ClassInfo> mClasses;
+    private boolean mExistsInBoth;
+    private SourcePositionInfo mPosition;
+    
+    public PackageInfo(String name, SourcePositionInfo position) {
+        mName = name;
+        mClasses = new HashMap<String, ClassInfo>();
+        mExistsInBoth = false;
+        mPosition = position;
+    }
+    
+    public void addClass(ClassInfo cl) {
+        mClasses.put(cl.name() , cl);
+    }
+    
+    public HashMap<String, ClassInfo> allClasses() {
+        return mClasses;
+    }
+    
+    public String name() {
+        return mName;
+    }
+    
+    public SourcePositionInfo position() {
+        return mPosition;
+    }
+    
+    public boolean isConsistent(PackageInfo pInfo) {
+        mExistsInBoth = true;
+        pInfo.mExistsInBoth = true;
+        boolean consistent = true;
+        for (ClassInfo cInfo : mClasses.values()) {
+            if (pInfo.mClasses.containsKey(cInfo.name())) {
+                if (!cInfo.isConsistent(pInfo.mClasses.get(cInfo.name()))) {
+                    consistent = false;
+                }
+            } else {
+                Errors.error(Errors.REMOVED_CLASS, cInfo.position(),
+                        "Removed public class " + cInfo.qualifiedName());
+                consistent = false;
+            }
+        }
+        for (ClassInfo cInfo : pInfo.mClasses.values()) {
+            if (!cInfo.isInBoth()) {
+                Errors.error(Errors.ADDED_CLASS, cInfo.position(),
+                        "Added class " + cInfo.name() + " to package "
+                        + pInfo.name());
+                consistent = false;
+            }
+        }
+        return consistent;
+    }
+    
+    public boolean isInBoth() {
+        return mExistsInBoth;
+    }
+}
diff --git a/build/tools/apicheck/src/com/android/apicheck/ParameterInfo.java b/build/tools/apicheck/src/com/android/apicheck/ParameterInfo.java
new file mode 100644 (file)
index 0000000..5788814
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.apicheck;
+
+public class ParameterInfo {
+    private String mType;
+    private String mName;
+    
+    public ParameterInfo(String type, String name) {
+        mType = type;
+        mName = name;
+    }
+    
+    public String getType() {
+        return mType;
+    }
+    
+    public String getName() {
+        return mName;
+    }
+}
diff --git a/build/tools/apicheck/src/com/android/apicheck/SourcePositionInfo.java b/build/tools/apicheck/src/com/android/apicheck/SourcePositionInfo.java
new file mode 100644 (file)
index 0000000..276771b
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.apicheck;
+
+import java.lang.Comparable;
+
+public class SourcePositionInfo implements Comparable
+{
+    public SourcePositionInfo() {
+        this.file = "<unknown>";
+        this.line = 0;
+        this.column = 0;
+    }
+
+    public SourcePositionInfo(String file, int line, int column)
+    {
+        this.file = file;
+        this.line = line;
+        this.column = column;
+    }
+
+    public SourcePositionInfo(SourcePositionInfo that)
+    {
+        this.file = that.file;
+        this.line = that.line;
+        this.column = that.column;
+    }
+
+    /**
+     * Given this position and str which occurs at that position, as well as str an index into str,
+     * find the SourcePositionInfo.
+     *
+     * @throw StringIndexOutOfBoundsException if index &gt; str.length()
+     */
+    public static SourcePositionInfo add(SourcePositionInfo that, String str, int index)
+    {
+        if (that == null) {
+            return null;
+        }
+        int line = that.line;
+        char prev = 0;
+        for (int i=0; i<index; i++) {
+            char c = str.charAt(i);
+            if (c == '\r' || (c == '\n' && prev != '\r')) {
+                line++;
+            }
+            prev = c;
+        }
+        return new SourcePositionInfo(that.file, line, 0);
+    }
+
+    public static SourcePositionInfo findBeginning(SourcePositionInfo that, String str)
+    {
+        if (that == null) {
+            return null;
+        }
+        int line = that.line-1; // -1 because, well, it seems to work
+        int prev = 0;
+        for (int i=str.length()-1; i>=0; i--) {
+            char c = str.charAt(i);
+            if ((c == '\r' && prev != '\n') || (c == '\n')) {
+                line--;
+            }
+            prev = c;
+        }
+        return new SourcePositionInfo(that.file, line, 0);
+    }
+
+    @Override
+    public String toString()
+    {
+        if (this.file == null) {
+            return "(unknown)";
+        } else {
+            if (this.line == 0) {
+                return this.file + ':';
+            } else {
+                return this.file + ':' + this.line + ':';
+            }
+        }
+    }
+
+    public int compareTo(Object o) {
+        SourcePositionInfo that = (SourcePositionInfo)o;
+        int r = this.file.compareTo(that.file);
+        if (r != 0) return r;
+        return this.line - that.line;
+    }
+
+    /**
+     * Build a SourcePositionInfo from the XML source= notation
+     */
+    public static SourcePositionInfo fromXml(String source) {
+        if (source != null) {
+            for (int i = 0; i < source.length(); i++) {
+                if (source.charAt(i) == ':') {
+                    return new SourcePositionInfo(source.substring(0, i),
+                            Integer.parseInt(source.substring(i+1)), 0);
+                }
+            }
+        }
+
+        return new SourcePositionInfo("(unknown)", 0, 0);
+    }
+
+    public String file;
+    public int line;
+    public int column;
+}
diff --git a/build/tools/apriori/Android.mk b/build/tools/apriori/Android.mk
new file mode 100644 (file)
index 0000000..79ecf7f
--- /dev/null
@@ -0,0 +1,61 @@
+# Copyright 2005 The Android Open Source Project
+#
+# Android.mk for apriori
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+ifneq ($(TARGET_SIMULATOR),true)
+include $(CLEAR_VARS)
+
+LOCAL_LDLIBS += -ldl
+LOCAL_CFLAGS += -O2 -g
+LOCAL_CFLAGS += -fno-function-sections -fno-data-sections -fno-inline
+LOCAL_CFLAGS += -Wall -Wno-unused-function #-Werror
+LOCAL_CFLAGS += -DSUPPORT_ANDROID_PRELINK_TAGS
+LOCAL_CFLAGS += -DDEBUG
+LOCAL_CFLAGS += -DADJUST_ELF=1
+
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_CFLAGS += -DARM_SPECIFIC_HACKS
+LOCAL_CFLAGS += -DBIG_ENDIAN=1
+endif
+
+ifeq ($(HOST_OS),darwin)
+LOCAL_CFLAGS += -DFSCANF_IS_BROKEN
+endif
+ifeq ($(HOST_OS),windows)
+LOCAL_CFLAGS += -DFSCANF_IS_BROKEN
+LOCAL_LDLIBS += -lintl
+endif
+
+
+
+LOCAL_SRC_FILES := \
+       apriori.c \
+       cmdline.c \
+       debug.c \
+       hash.c \
+       main.c \
+       prelink_info.c \
+       rangesort.c \
+       source.c \
+       prelinkmap.c
+
+LOCAL_C_INCLUDES:= \
+       $(LOCAL_PATH)/ \
+       external/elfutils/lib/ \
+       external/elfutils/libelf/ \
+       external/elfutils/libebl/ \
+       external/elfcopy/
+
+LOCAL_STATIC_LIBRARIES := libelfcopy libelf libebl #dl
+
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_STATIC_LIBRARIES += libebl_arm
+endif
+
+LOCAL_MODULE := apriori
+
+include $(BUILD_HOST_EXECUTABLE)
+endif # TARGET_SIMULATOR != true
diff --git a/build/tools/apriori/apriori.c b/build/tools/apriori/apriori.c
new file mode 100644 (file)
index 0000000..d1807b3
--- /dev/null
@@ -0,0 +1,2601 @@
+#include <stdio.h>
+#include <common.h>
+#include <debug.h>
+#include <libelf.h>
+#include <libebl.h>
+#ifdef ARM_SPECIFIC_HACKS
+    #include <libebl_arm.h>
+#endif/*ARM_SPECIFIC_HACKS*/
+#include <elf.h>
+#include <gelf.h>
+#include <string.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <hash.h>
+#include <apriori.h>
+#include <source.h>
+#include <tweak.h>
+#include <rangesort.h>
+#include <prelink_info.h>
+#include <prelinkmap.h>
+#include <libgen.h>
+
+#ifndef ADJUST_ELF
+#error "ADJUST_ELF must be defined!"
+#endif
+
+/* When this macro is defined, apriori sets to ZERO those relocation values for
+   which it canot find the appropriate referent.
+*/
+#define PERMISSIVE
+#define COPY_SECTION_DATA_BUFFER (0)
+/* When this macro is set to a nonzero value, we replace calls to elf_strptr()
+   on the target ELF handle with code that extracts the strings directly from
+   the data buffers of that ELF handle.  In this case, elf_strptr() does not
+   work as expected, as it tries to read the data buffer of the associated
+   string section directly from the file, and that buffer does not exist yet
+   in the file, since we haven't committed our changes yet.
+*/
+#define ELF_STRPTR_IS_BROKEN     (1)
+
+/* When the macro below is defined, apriori does not mark for removal those
+   relocation sections that it fully handles.  Instead, apriori just sets their
+   sizes to zero.  This is more for debugging than of any actual use.
+
+   This macro is meaningful only when ADJUST_ELF!=0
+*/
+#define REMOVE_HANDLED_SECTIONS
+
+extern int verbose_flag;
+
+static source_t *sources = NULL;
+
+#if defined(DEBUG) && 0
+
+static void print_shdr(source_t *source, Elf_Scn *scn)
+{
+    GElf_Shdr shdr_mem, *shdr;
+    shdr = gelf_getshdr(scn, &shdr_mem);
+    Elf_Data *data = elf_getdata(scn, NULL);
+    INFO("\t%02d: data = %p, hdr = { offset = %8lld, size = %lld }, "
+         "data->d_buf = %p data->d_off = %lld, data->d_size = %d\n",
+         elf_ndxscn(scn),
+         data,
+         shdr->sh_offset, shdr->sh_size,
+         data->d_buf, data->d_off, data->d_size);
+}
+
+static void print_shdr_idx(source_t *source, Elf *elf, int idx)
+{
+    print_shdr(source, elf_getscn(elf, idx));
+}
+
+static void print_shdrs(source_t *source) {
+  Elf_Scn *scn = NULL;
+  INFO("section offset dump for new ELF\n");
+  while ((scn = elf_nextscn (source->elf, scn)) != NULL)
+    print_shdr(source, scn);
+
+  INFO("\nsection offset dump for original ELF\n");
+  while ((scn = elf_nextscn (source->oldelf, scn)) != NULL)
+    print_shdr(source, scn);
+
+#if 0
+  {
+    INFO("section offset dump for new ELF\n");
+    int i = 0;
+    for (i = 0; i < source->shnum; i++) {
+      scn = elf_getscn(source->elf, i);
+      print_shdr(source, scn);
+    }
+  }
+#endif
+}
+
+#endif /* DEBUG */
+
+static char * find_file(const char *libname,
+                        char **lib_lookup_dirs,
+                        int num_lib_lookup_dirs);
+
+static inline source_t* find_source(const char *name,
+                                    char **lib_lookup_dirs,
+                                    int num_lib_lookup_dirs) {
+    char *full = find_file(name, lib_lookup_dirs, num_lib_lookup_dirs);
+    if (full) {
+        source_t *trav = sources;
+        while (trav) {
+            if (!strcmp(trav->name, full))
+                break;
+            trav = trav->next;
+        }
+        free(full);
+        return trav;
+    }
+    return NULL;
+}
+
+static inline void add_to_sources(source_t *src) {
+    src->next = sources;
+    sources = src;
+}
+
+static void handle_range_error(range_error_t err,
+                               range_t *left, range_t *right) {
+    switch (err) {
+    case ERROR_CONTAINS:
+        ERROR("ERROR: section (%lld, %lld bytes) contains "
+              "section (%lld, %lld bytes)\n",
+              left->start, left->length,
+              right->start, right->length);
+        break;
+    case ERROR_OVERLAPS:
+        ERROR("ERROR: Section (%lld, %lld bytes) intersects "
+              "section (%lld, %lld bytes)\n",
+              left->start, left->length,
+              right->start, right->length);
+        break;
+    default:
+        ASSERT(!"Unknown range error code!");
+    }
+
+    FAILIF(1, "Range error.\n");
+}
+
+static void create_elf_sections(source_t *source, Elf *elf)
+{
+    INFO("Creating new ELF sections.\n");
+    ASSERT(elf == NULL || source->elf == NULL || source->elf == elf);
+    if (elf == NULL) {
+        ASSERT(source->elf != NULL);
+        elf = source->elf;
+    }
+
+    int cnt = 1;
+    Elf_Scn *oldscn = NULL, *scn;
+    while ((oldscn = elf_nextscn (source->oldelf, oldscn)) != NULL) {
+        GElf_Shdr *oldshdr, oldshdr_mem;
+
+        scn = elf_newscn(elf);
+        FAILIF_LIBELF(NULL == scn, elf_newscn);
+
+        oldshdr = gelf_getshdr(oldscn, &oldshdr_mem);
+        FAILIF_LIBELF(NULL == oldshdr, gelf_getshdr);
+        /* Set the section header of the new section to be the same as the
+           headset of the old section by default. */
+        gelf_update_shdr(scn, oldshdr);
+
+        /* Copy the section data */
+        Elf_Data *olddata = elf_getdata(oldscn, NULL);
+        FAILIF_LIBELF(NULL == olddata, elf_getdata);
+
+        Elf_Data *data = elf_newdata(scn);
+        FAILIF_LIBELF(NULL == data, elf_newdata);
+        *data = *olddata;
+#if COPY_SECTION_DATA_BUFFER
+        if (olddata->d_buf != NULL) {
+            data->d_buf = MALLOC(data->d_size);
+            memcpy(data->d_buf, olddata->d_buf, olddata->d_size);
+        }
+#endif
+
+        INFO("\tsection %02d: [%-30s] created\n",
+             cnt,
+             elf_strptr(source->oldelf,
+                        source->shstrndx,
+                        oldshdr->sh_name));
+
+        if (ADJUST_ELF) {
+            ASSERT(source->shdr_info != NULL);
+            /* Create a new section. */
+            source->shdr_info[cnt].idx = cnt;
+            source->shdr_info[cnt].newscn = scn;
+            source->shdr_info[cnt].data = data;
+            source->shdr_info[cnt].
+                use_old_shdr_for_relocation_calculations = 1;
+            INFO("\tsection [%s]  (old offset %lld, old size %lld) "
+                 "will have index %d (was %d).\n",
+                 source->shdr_info[cnt].name,
+                 source->shdr_info[cnt].old_shdr.sh_offset,
+                 source->shdr_info[cnt].old_shdr.sh_size,
+                 source->shdr_info[cnt].idx,
+                 elf_ndxscn(source->shdr_info[cnt].scn));
+            /* Same as the next assert */
+            ASSERT(elf_ndxscn (source->shdr_info[cnt].newscn) ==
+                   source->shdr_info[cnt].idx);
+        }
+
+        ASSERT(elf_ndxscn(scn) == (size_t)cnt);
+        cnt++;
+    }
+}
+
+/* This function sets up the shdr_info[] array of a source_t.  We call it only
+   when ADJUST_ELF is non-zero (i.e., support for adjusting an ELF file for
+   changes in sizes and numbers of relocation sections is compiled in.  Note
+   that setup_shdr_info() depends only on the information in source->oldelf,
+   not on source->elf.
+*/
+
+static void setup_shdr_info(source_t *source)
+{
+    if (ADJUST_ELF)
+    {
+        /* Allocate the section-header-info buffer. */
+        INFO("Allocating section-header info structure (%d) bytes...\n",
+             source->shnum * sizeof (shdr_info_t));
+
+        source->shdr_info = (shdr_info_t *)CALLOC(source->shnum,
+                                                  sizeof (shdr_info_t));
+
+        /* Mark the SHT_NULL section as handled. */
+        source->shdr_info[0].idx = 2;
+
+        int cnt = 1;
+        Elf_Scn *oldscn = NULL;
+        while ((oldscn = elf_nextscn (source->oldelf, oldscn)) != NULL) {
+            /* Copy the section header */
+            ASSERT(elf_ndxscn(oldscn) == (size_t)cnt);
+
+            /* Initialized the corresponding shdr_info entry */
+            {
+                /* Mark the section with a non-zero index.  Later, when we
+                   decide to drop a section, we will set its idx to zero, and
+                   assign section numbers to the remaining sections.
+                */
+                source->shdr_info[cnt].idx = 1;
+
+                source->shdr_info[cnt].scn = oldscn;
+
+                /* NOTE: Here we pupulate the section-headset struct with the
+                         same values as the original section's.  After the
+                         first run of prelink(), we will update the sh_size
+                         fields of those sections that need resizing.
+                */
+                FAILIF_LIBELF(NULL == 
+                              gelf_getshdr(oldscn,
+                                           &source->shdr_info[cnt].shdr),
+                              gelf_getshdr);
+                
+                /* Get the name of the section. */
+                source->shdr_info[cnt].name =
+                    elf_strptr (source->oldelf, source->shstrndx,
+                                source->shdr_info[cnt].shdr.sh_name);
+
+                INFO("\tname: %s\n", source->shdr_info[cnt].name);
+                FAILIF(source->shdr_info[cnt].name == NULL,
+                       "Malformed file: section %d name is null\n",
+                       cnt);
+
+                /* Remember the shdr.sh_link value.  We need to remember this
+                   value for those sections that refer to other sections.  For
+                   example, we need to remember it for relocation-entry
+                   sections, because if we modify the symbol table that a
+                   relocation-entry section is relative to, then we need to
+                   patch the relocation section.  By the time we get to
+                   deciding whether we need to patch the relocation section, we
+                   will have overwritten its header's sh_link field with a new
+                   value.
+                */
+                source->shdr_info[cnt].old_shdr = source->shdr_info[cnt].shdr;
+                INFO("\t\toriginal sh_link: %08d\n",
+                     source->shdr_info[cnt].old_shdr.sh_link);
+                INFO("\t\toriginal sh_addr: %lld\n",
+                     source->shdr_info[cnt].old_shdr.sh_addr);
+                INFO("\t\toriginal sh_offset: %lld\n",
+                     source->shdr_info[cnt].old_shdr.sh_offset);
+                INFO("\t\toriginal sh_size: %lld\n",
+                     source->shdr_info[cnt].old_shdr.sh_size);
+
+                FAILIF(source->shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX,
+                       "Cannot handle sh_type SHT_SYMTAB_SHNDX!\n");
+                FAILIF(source->shdr_info[cnt].shdr.sh_type == SHT_GROUP,
+                       "Cannot handle sh_type SHT_GROUP!\n");
+                FAILIF(source->shdr_info[cnt].shdr.sh_type == SHT_GNU_versym,
+                       "Cannot handle sh_type SHT_GNU_versym!\n");
+            }
+
+            cnt++;
+        } /* for each section */
+    } /* if (ADJUST_ELF) */
+}
+
+static Elf * init_elf(source_t *source, bool create_new_sections)
+{
+    Elf *elf;
+    if (source->output != NULL) {
+        if (source->output_is_dir) {
+            source->output_is_dir++;
+            char *dir = source->output;
+            int dirlen = strlen(dir);
+            /* The main() function maintains a pointer to source->output; it
+               frees the buffer after apriori() returns.
+            */
+            source->output = MALLOC(dirlen +
+                                    1 + /* slash */
+                                    strlen(source->name) +
+                                    1); /* null terminator */
+            strcpy(source->output, dir);
+            source->output[dirlen] = '/';
+            strcpy(source->output + dirlen + 1,
+                   basename(source->name));
+        }
+
+        source->newelf_fd = open(source->output,
+                                 O_RDWR | O_CREAT,
+                                 0666);
+        FAILIF(source->newelf_fd < 0, "open(%s): %s (%d)\n",
+               source->output,
+               strerror(errno),
+               errno);
+        elf = elf_begin(source->newelf_fd, ELF_C_WRITE, NULL);
+        FAILIF_LIBELF(elf == NULL, elf_begin);
+    } else {
+        elf = elf_clone(source->oldelf, ELF_C_EMPTY);
+        FAILIF_LIBELF(elf == NULL, elf_clone);
+    }
+
+    GElf_Ehdr *oldehdr = gelf_getehdr(source->oldelf, &source->old_ehdr_mem);
+    FAILIF_LIBELF(NULL == oldehdr, gelf_getehdr);
+
+    /* Create new ELF and program headers for the elf file */
+    INFO("Creating empty ELF and program headers...\n");
+    FAILIF_LIBELF(gelf_newehdr (elf, gelf_getclass (source->oldelf)) == 0,
+                  gelf_newehdr);
+    FAILIF_LIBELF(oldehdr->e_type != ET_REL
+                  && gelf_newphdr (elf,
+                                   oldehdr->e_phnum) == 0,
+                  gelf_newphdr);
+
+    /* Copy the elf header */
+    INFO("Copying ELF header...\n");
+    GElf_Ehdr *ehdr = gelf_getehdr(elf, &source->ehdr_mem);
+    FAILIF_LIBELF(NULL == ehdr, gelf_getehdr);
+    memcpy(ehdr, oldehdr, sizeof(GElf_Ehdr));
+    FAILIF_LIBELF(!gelf_update_ehdr(elf, ehdr), gelf_update_ehdr);
+
+    /* Copy out the old program header: notice that if the ELF file does not
+       have a program header, this loop won't execute.
+    */
+    INFO("Copying ELF program header...\n");
+    {
+        int cnt;
+        source->phdr_info = (GElf_Phdr *)CALLOC(ehdr->e_phnum,
+                                                sizeof(GElf_Phdr));
+        for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) {
+            INFO("\tRetrieving entry %d\n", cnt);
+            FAILIF_LIBELF(NULL ==
+                          gelf_getphdr(source->oldelf, cnt,
+                                       source->phdr_info + cnt),
+                          gelf_getphdr);
+            FAILIF_LIBELF(gelf_update_phdr (elf, cnt, 
+                                            source->phdr_info + cnt) == 0,
+                          gelf_update_phdr);
+        }
+    }
+
+    /* Copy the sections and the section headers. */
+    if (create_new_sections)
+    {
+        create_elf_sections(source, elf);
+    }
+
+    /* The ELF library better follows our layout when this is not a
+       relocatable object file. */
+    elf_flagelf (elf, ELF_C_SET, (ehdr->e_type != ET_REL ? ELF_F_LAYOUT : 0));
+
+    return elf;
+}
+
+static shdr_info_t *lookup_shdr_info_by_new_section(
+    source_t *source,
+    const char *sname,
+    Elf_Scn *newscn)
+{
+    if (source->shdr_info == NULL) return NULL;
+    int cnt;
+    for (cnt = 0; cnt < source->shnum; cnt++) {
+        if (source->shdr_info[cnt].newscn == newscn) {
+            INFO("\t\tnew section at %p matches shdr_info[%d], "
+                 "section [%s]!\n",
+                 newscn,
+                 cnt,
+                 source->shdr_info[cnt].name);
+            FAILIF(strcmp(sname, source->shdr_info[cnt].name),
+                   "Matched section's name [%s] does not match "
+                   "looked-up section's name [%s]!\n",
+                   source->shdr_info[cnt].name,
+                   sname);
+            return source->shdr_info + cnt;
+        }
+    }
+    return NULL;
+}
+
+static bool do_init_source(source_t *source, unsigned base)
+{
+    /* Find various sections. */
+    size_t scnidx;
+    Elf_Scn *scn;
+    GElf_Shdr *shdr, shdr_mem;
+    source->sorted_sections = init_range_list();
+    INFO("Processing [%s]'s sections...\n", source->name);
+    for (scnidx = 1; scnidx < (size_t)source->shnum; scnidx++) {
+        INFO("\tGetting section index %d...\n", scnidx);
+        scn = elf_getscn(source->elf, scnidx);
+        if (NULL == scn) {
+            /* If we get an error from elf_getscn(), it means that a section
+               at the requested index does not exist.  This may happen when
+               we remove sections.  Since we do not update source->shnum
+               (we can't, since we need to know the original number of sections
+               to know source->shdr_info[]'s length), we will attempt to
+               retrieve a section for an index that no longer exists in the
+               new ELF file. */
+            INFO("\tThere is no section at index %d anymore, continuing.\n",
+                 scnidx);
+            continue;
+        }
+        shdr = gelf_getshdr(scn, &shdr_mem);
+        FAILIF_LIBELF(NULL == shdr, gelf_getshdr);
+
+        /* We haven't modified the shstrtab section, and so shdr->sh_name
+           has the same value as before.  Thus we look up the name based
+           on the old ELF handle.  We cannot use shstrndx on the new ELF
+           handle because the index of the shstrtab section may have
+           changed (and calling elf_getshstrndx() returns the same section
+           index, so libelf can't handle thise ither).
+        */
+        const char *sname =
+          elf_strptr(source->oldelf, source->shstrndx, shdr->sh_name);
+        ASSERT(sname);
+
+        INFO("\tAdding [%s] (%lld, %lld)...\n",
+             sname,
+             shdr->sh_addr,
+             shdr->sh_addr + shdr->sh_size);
+        if ((shdr->sh_flags & SHF_ALLOC) == SHF_ALLOC) {
+            add_unique_range_nosort(source->sorted_sections,
+                                    shdr->sh_addr,
+                                    shdr->sh_size,
+                                    scn,
+                                    handle_range_error,
+                                    NULL); /* no user-data destructor */
+        }
+
+        if (shdr->sh_type == SHT_DYNSYM) {
+            source->symtab.scn = scn;
+            source->symtab.data = elf_getdata(scn, NULL);
+            FAILIF_LIBELF(NULL == source->symtab.data, elf_getdata);
+            memcpy(&source->symtab.shdr, shdr, sizeof(GElf_Shdr));
+            source->symtab.info = lookup_shdr_info_by_new_section(
+                source, sname, scn);
+            ASSERT(source->shdr_info == NULL || source->symtab.info != NULL);
+
+            /* The sh_link field of the section header of the symbol table
+               contains the index of the associated strings table. */
+            source->strtab.scn = elf_getscn(source->elf,
+                                            source->symtab.shdr.sh_link);
+            FAILIF_LIBELF(NULL == source->strtab.scn, elf_getscn);
+            FAILIF_LIBELF(NULL == gelf_getshdr(source->strtab.scn,
+                                               &source->strtab.shdr),
+                          gelf_getshdr);
+            source->strtab.data = elf_getdata(source->strtab.scn, NULL);
+            FAILIF_LIBELF(NULL == source->strtab.data, elf_getdata);
+            source->strtab.info = lookup_shdr_info_by_new_section(
+                source,
+                elf_strptr(source->oldelf, source->shstrndx,
+                           source->strtab.shdr.sh_name),
+                source->strtab.scn);
+            ASSERT(source->shdr_info == NULL || source->strtab.info != NULL);
+        } else if (shdr->sh_type == SHT_DYNAMIC) {
+            source->dynamic.scn = scn;
+            source->dynamic.data = elf_getdata(scn, NULL);
+            FAILIF_LIBELF(NULL == source->dynamic.data, elf_getdata);
+            memcpy(&source->dynamic.shdr, shdr, sizeof(GElf_Shdr));
+            source->dynamic.info = lookup_shdr_info_by_new_section(
+                source, sname, scn);
+            ASSERT(source->shdr_info == NULL || source->dynamic.info != NULL);
+        } else if (shdr->sh_type == SHT_HASH) {
+            source->hash.scn = scn;
+            source->hash.data = elf_getdata(scn, NULL);
+            FAILIF_LIBELF(NULL == source->hash.data, elf_getdata);
+            memcpy(&source->hash.shdr, shdr, sizeof(GElf_Shdr));
+            source->hash.info = lookup_shdr_info_by_new_section(
+                source, sname, scn);
+            ASSERT(source->shdr_info == NULL || source->hash.info != NULL);
+        } else if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) {
+            if (source->num_relocation_sections ==
+                    source->relocation_sections_size) {
+                source->relocation_sections_size += 5;
+                source->relocation_sections =
+                (section_info_t *)REALLOC(source->relocation_sections,
+                                          source->relocation_sections_size *
+                                          sizeof(section_info_t));
+            }
+            section_info_t *reloc =
+            source->relocation_sections + source->num_relocation_sections;
+            reloc->scn = scn;
+            reloc->info = lookup_shdr_info_by_new_section(source, sname, scn);
+            ASSERT(source->shdr_info == NULL || reloc->info != NULL);
+            reloc->data = elf_getdata(scn, NULL);
+            FAILIF_LIBELF(NULL == reloc->data, elf_getdata);
+            memcpy(&reloc->shdr, shdr, sizeof(GElf_Shdr));
+            source->num_relocation_sections++;
+        } else if (!strcmp(sname, ".bss")) {
+            source->bss.scn = scn;
+            source->bss.data = elf_getdata(scn, NULL);
+            source->bss.info = lookup_shdr_info_by_new_section(
+                source, sname, scn);
+            ASSERT(source->shdr_info == NULL || source->bss.info != NULL);
+            /* The BSS section occupies no space in the ELF file. */
+            FAILIF_LIBELF(NULL == source->bss.data, elf_getdata)
+            FAILIF(NULL != source->bss.data->d_buf,
+                   "Enexpected: section [%s] has data!",
+                   sname);
+            memcpy(&source->bss.shdr, shdr, sizeof(GElf_Shdr));
+        }
+    }
+    sort_ranges(source->sorted_sections);
+
+    source->unfinished =
+        (unfinished_relocation_t *)CALLOC(source->num_relocation_sections,
+                                          sizeof(unfinished_relocation_t));
+
+    if (source->dynamic.scn == NULL) {
+        INFO("File [%s] does not have a dynamic section!\n", source->name);
+        /* If this is a static executable, we won't update anything. */
+        source->dry_run = 1;
+        return false;
+    }
+
+    FAILIF(source->symtab.scn == NULL,
+           "File [%s] does not have a dynamic symbol table!\n",
+           source->name);
+    FAILIF(source->hash.scn == NULL,
+           "File [%s] does not have a hash table!\n",
+           source->name);
+    FAILIF(source->hash.shdr.sh_link != elf_ndxscn(source->symtab.scn),
+           "Hash points to section %d, not to %d as expected!\n",
+           source->hash.shdr.sh_link,
+           elf_ndxscn(source->symtab.scn));
+
+    /* Now, find out how many symbols we have and allocate the array of
+       satisfied symbols.
+
+       NOTE: We don't count the number of undefined symbols here; we will
+       iterate over the symbol table later, and count them then, when it is
+       more convenient.
+    */
+    size_t symsize = gelf_fsize (source->elf,
+                                 ELF_T_SYM,
+                                 1, source->elf_hdr.e_version);
+    ASSERT(symsize);
+
+    source->num_syms = source->symtab.data->d_size / symsize;
+    source->base = (source->oldelf_hdr.e_type == ET_DYN) ? base : 0;
+    INFO("Relink base for [%s]: 0x%lx\n", source->name, source->base);
+    FAILIF(source->base == -1,
+           "Can't prelink [%s]: it's a shared library and you did not "
+           "provide a prelink address!\n",
+           source->name);
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+    FAILIF(source->prelinked && source->base != source->prelink_base,
+           "ERROR: file [%s] has already been prelinked for 0x%08lx.  "
+           "Cannot change to 0x%08lx!\n",
+           source->name,
+           source->prelink_base,
+           source->base);
+#endif/*SUPPORT_ANDROID_PRELINK_TAGS*/
+
+    return true;
+}
+
+static source_t* init_source(const char *full_path,
+                             const char *output, int is_file,
+                             int base, int dry_run)
+{
+    source_t *source = (source_t *)CALLOC(1, sizeof(source_t));
+
+    ASSERT(full_path);
+    source->name = full_path;
+    source->output = output;
+    source->output_is_dir = !is_file;
+
+    source->newelf_fd = -1;
+    source->elf_fd = -1;
+    INFO("Opening %s...\n", full_path);
+    source->elf_fd =
+        open(full_path, ((dry_run || output != NULL) ? O_RDONLY : O_RDWR));
+    FAILIF(source->elf_fd < 0, "open(%s): %s (%d)\n",
+           full_path,
+           strerror(errno),
+           errno);
+
+       FAILIF(fstat(source->elf_fd, &source->elf_file_info) < 0,
+                  "fstat(%s(fd %d)): %s (%d)\n",
+                  source->name,
+                  source->elf_fd,
+                  strerror(errno),
+                  errno);
+       INFO("File [%s]'s size is %lld bytes!\n",
+                source->name,
+                source->elf_file_info.st_size);
+
+    INFO("Calling elf_begin(%s)...\n", full_path);
+
+    source->oldelf =
+        elf_begin(source->elf_fd,
+                  (dry_run || output != NULL) ? ELF_C_READ : ELF_C_RDWR,
+                  NULL);
+    FAILIF_LIBELF(source->oldelf == NULL, elf_begin);
+
+    /* libelf can recognize COFF and A.OUT formats, but we handle only ELF. */
+    if(elf_kind(source->oldelf) != ELF_K_ELF) {
+        ERROR("Input file %s is not in ELF format!\n", full_path);
+        return NULL;
+    }
+
+    /* Make sure this is a shared library or an executable. */
+    {
+        INFO("Making sure %s is a shared library or an executable...\n",
+             full_path);
+        FAILIF_LIBELF(0 == gelf_getehdr(source->oldelf, &source->oldelf_hdr),
+                      gelf_getehdr);
+        FAILIF(source->oldelf_hdr.e_type != ET_DYN &&
+               source->oldelf_hdr.e_type != ET_EXEC,
+               "%s must be a shared library (elf type is %d, expecting %d).\n",
+               full_path,
+               source->oldelf_hdr.e_type,
+               ET_DYN);
+    }
+
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+    /* First, check to see if the file has been prelinked. */
+    source->prelinked =
+        check_prelinked(source->name,
+                        source->oldelf_hdr.e_ident[EI_DATA] == ELFDATA2LSB,
+                        &source->prelink_base);
+    /* Note that in the INFO() below we need to use oldelf_hdr because we
+       haven't cloned the ELF file yet, and source->elf_hdr is not defined. */
+    if (source->prelinked) {
+        PRINT("%s [%s] is already prelinked at 0x%08lx!\n",
+              (source->oldelf_hdr.e_type == ET_EXEC ?
+               "Executable" : "Shared library"),
+              source->name,
+              source->prelink_base);
+        /* Force a dry run when the file has already been prelinked */
+        source->dry_run = dry_run = 1;
+    }
+    else {
+        INFO("%s [%s] is not prelinked!\n",
+             (source->oldelf_hdr.e_type == ET_EXEC ?
+              "Executable" : "Shared library"),
+             source->name);
+        source->dry_run = dry_run;
+    }
+#endif/*SUPPORT_ANDROID_PRELINK_TAGS*/
+
+    /* Get the index of the section-header-strings-table section. */
+    FAILIF_LIBELF(elf_getshstrndx (source->oldelf, &source->shstrndx) < 0,
+                  elf_getshstrndx);
+
+    FAILIF_LIBELF(elf_getshnum (source->oldelf, (size_t *)&source->shnum) < 0,
+                  elf_getshnum);
+
+    /* When we have a dry run, or when ADJUST_ELF is enabled, we use
+       source->oldelf for source->elf, because the former is mmapped privately,
+       so changes to it have no effect.  With ADJUST_ELF, the first run of
+       prelink() is a dry run.  We will reopen the elf file for write access
+       after that dry run, before we call adjust_elf. */
+
+    source->elf = (ADJUST_ELF || source->dry_run) ?
+        source->oldelf : init_elf(source, ADJUST_ELF == 0);
+
+    FAILIF_LIBELF(0 == gelf_getehdr(source->elf, &source->elf_hdr),
+                  gelf_getehdr);
+#ifdef DEBUG
+    ASSERT(!memcmp(&source->oldelf_hdr,
+                   &source->elf_hdr,
+                   sizeof(source->elf_hdr)));
+#endif
+
+    /* Get the EBL handling.  The -g option is currently the only reason
+       we need EBL so dont open the backend unless necessary.  */
+    source->ebl = ebl_openbackend (source->elf);
+    FAILIF_LIBELF(NULL == source->ebl, ebl_openbackend);
+#ifdef ARM_SPECIFIC_HACKS
+    FAILIF_LIBELF(0 != arm_init(source->elf, source->elf_hdr.e_machine,
+                                source->ebl, sizeof(Ebl)),
+                  arm_init);
+#endif/*ARM_SPECIFIC_HACKS*/
+
+    add_to_sources(source);
+    if (do_init_source(source, base) == false) return NULL;
+    return source;
+}
+
+/* complements do_init_source() */
+static void do_destroy_source(source_t *source)
+{
+    int cnt;
+    destroy_range_list(source->sorted_sections);
+    source->sorted_sections = NULL;
+    for (cnt = 0; cnt < source->num_relocation_sections; cnt++) {
+        FREEIF(source->unfinished[cnt].rels);
+        source->unfinished[cnt].rels = NULL;
+        source->unfinished[cnt].num_rels = 0;
+        source->unfinished[cnt].rels_size = 0;
+    }
+    if (source->jmprel.sections != NULL) {
+        destroy_range_list(source->jmprel.sections);
+        source->jmprel.sections = NULL;
+    }
+    if (source->rel.sections != NULL) {
+        destroy_range_list(source->rel.sections);
+        source->rel.sections = NULL;
+    }
+    FREE(source->unfinished); /* do_init_source() */
+    source->unfinished = NULL;
+    FREE(source->relocation_sections); /* do_init_source() */
+    source->relocation_sections = NULL;
+    source->num_relocation_sections = source->relocation_sections_size = 0;
+}
+
+static void destroy_source(source_t *source)
+{
+    /* Is this a little-endian ELF file? */
+    if (source->oldelf != source->elf) {
+        /* If it's a dynamic executable, this must not be a dry run. */
+        if (!source->dry_run && source->dynamic.scn != NULL)
+        {
+            FAILIF_LIBELF(elf_update(source->elf, ELF_C_WRITE) == -1,
+                          elf_update);
+        }
+        FAILIF_LIBELF(elf_end(source->oldelf), elf_end);
+    }
+    ebl_closebackend(source->ebl);
+    FAILIF_LIBELF(elf_end(source->elf), elf_end);
+    FAILIF(close(source->elf_fd) < 0, "Could not close file %s: %s (%d)!\n",
+           source->name, strerror(errno), errno);
+    FAILIF((source->newelf_fd >= 0) && (close(source->newelf_fd) < 0),
+           "Could not close output file: %s (%d)!\n", strerror(errno), errno);
+
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+    if (!source->dry_run) {
+        if (source->dynamic.scn != NULL &&
+            source->elf_hdr.e_type != ET_EXEC)
+        {
+            /* For some reason, trying to write directly to source->elf_fd
+               causes a "bad file descriptor" error because of something libelf
+               does.  We just close the file descriptor and open a new one in
+               function setup_prelink_info() below. */
+            INFO("%s: setting up prelink tag at end of file.\n",
+                 source->output ? source->output : source->name);
+            setup_prelink_info(source->output ? source->output : source->name,
+                               source->elf_hdr.e_ident[EI_DATA] == ELFDATA2LSB,
+                               source->base);
+        }
+        else INFO("%s: executable, NOT setting up prelink tag.\n",
+                  source->name);
+    }
+#endif/*SUPPORT_ANDROID_PRELINK_TAGS*/
+
+    do_destroy_source(source);
+
+    if (source->shstrtab_data != NULL)
+        FREEIF(source->shstrtab_data->d_buf); /* adjust_elf */
+
+    FREE(source->lib_deps); /* list of library dependencies (process_file()) */
+    FREEIF(source->shdr_info); /* setup_shdr_info() */
+    FREEIF(source->phdr_info); /* init_elf() */
+    FREE(source->name); /* assigned to by init_source() */
+    /* If the output is a directory, in init_elf() we allocate a buffer where
+       we copy the directory, a slash, and the file name.  Here we free that
+       buffer.
+    */
+    if (source->output_is_dir > 1) {
+        FREE(source->output);
+    }
+    FREE(source); /* init_source() */
+}
+
+static void reinit_source(source_t *source)
+{
+    do_destroy_source(source);
+    do_init_source(source, source->base);
+
+    {
+        /* We've gathered all the DT_DYNAMIC entries; now we need to figure
+           out which relocation sections fit in which range as described by
+           the entries.  Before we do so, however, we will populate the
+           jmprel and rel members of source, as well as their sizes.
+        */
+
+        size_t dynidx, numdyn;
+        GElf_Dyn *dyn, dyn_mem;
+
+        numdyn = source->dynamic.shdr.sh_size /
+            source->dynamic.shdr.sh_entsize;
+
+        source->rel.idx = source->rel.sz_idx = -1;
+        source->jmprel.idx = source->jmprel.sz_idx = -1;
+        for (dynidx = 0; dynidx < numdyn; dynidx++) {
+            dyn = gelf_getdyn (source->dynamic.data,
+                               dynidx,
+                               &dyn_mem);
+            FAILIF_LIBELF(NULL == dyn, gelf_getdyn);
+            switch (dyn->d_tag)
+            {
+            case DT_NEEDED:
+                break;
+            case DT_JMPREL:
+                INFO("reinit_source: DT_JMPREL is at index %d, 0x%08llx.\n",
+                     dynidx, dyn->d_un.d_ptr);
+                source->jmprel.idx = dynidx;
+                source->jmprel.addr = dyn->d_un.d_ptr;
+                break;
+            case DT_PLTRELSZ:
+                INFO("reinit_source: DT_PLTRELSZ is at index %d, 0x%08llx.\n",
+                     dynidx, dyn->d_un.d_val);
+                source->jmprel.sz_idx = dynidx;
+                source->jmprel.size = dyn->d_un.d_val;
+                break;
+            case DT_REL:
+                INFO("reinit_source: DT_REL is at index %d, 0x%08llx.\n",
+                     dynidx, dyn->d_un.d_ptr);
+                source->rel.idx = dynidx;
+                source->rel.addr = dyn->d_un.d_ptr;
+                break;
+            case DT_RELSZ:
+                INFO("reinit_source: DT_RELSZ is at index %d, 0x%08llx.\n",
+                     dynidx, dyn->d_un.d_val);
+                source->rel.sz_idx = dynidx;
+                source->rel.size = dyn->d_un.d_val;
+                break;
+            case DT_RELA:
+            case DT_RELASZ:
+                FAILIF(1, "Can't handle DT_RELA and DT_RELASZ entries!\n");
+                break;
+            } /* switch */
+        } /* for each dynamic entry... */
+    }
+}
+
+static GElf_Sym *hash_lookup_global_or_weak_symbol(source_t *lib,
+                                                   const char *symname,
+                                                   GElf_Sym *lib_sym_mem)
+{
+    int lib_symidx = hash_lookup(lib->elf,
+                                 lib->hash.data,
+                                 lib->symtab.data,
+                                 lib->strtab.data,
+                                 symname);
+
+    GElf_Sym sym_mem;
+    if (SHN_UNDEF != lib_symidx) {
+        /* We found the symbol--now check to see if it is global
+           or weak.  If this is the case, then the symbol satisfies
+           the dependency. */
+        GElf_Sym *lib_sym = gelf_getsymshndx(lib->symtab.data,
+                                             NULL,
+                                             lib_symidx,
+                                             &sym_mem,
+                                             NULL);
+        FAILIF_LIBELF(NULL == lib_sym, gelf_getsymshndx);
+#if ELF_STRPTR_IS_BROKEN
+        ASSERT(!strcmp(
+                   symname,
+                   ((char *)elf_getdata(elf_getscn(lib->elf,
+                                                   lib->symtab.shdr.sh_link),
+                                        NULL)->d_buf) +
+                   lib_sym->st_name));
+#else
+        ASSERT(!strcmp(
+                   symname,
+                   elf_strptr(lib->elf, lib->symtab.shdr.sh_link,
+                              lib_sym->st_name)));
+#endif
+        if (lib_sym->st_shndx != SHN_UNDEF &&
+            (GELF_ST_BIND(lib_sym->st_info) == STB_GLOBAL ||
+             GELF_ST_BIND(lib_sym->st_info) == STB_WEAK)) {
+            memcpy(lib_sym_mem, &sym_mem, sizeof(GElf_Sym));
+            return lib_sym;
+        }
+    }
+
+    return NULL;
+}
+
+static source_t *lookup_symbol_in_dependencies(source_t *source,
+                                               const char *symname,
+                                               GElf_Sym *found_sym)
+{
+    source_t *sym_source = NULL; /* return value */
+
+    /* This is an undefined symbol.  Go over the list of libraries
+       and look it up. */
+    size_t libidx;
+    int found = 0;
+    source_t *last_found = NULL;
+    for (libidx = 0; libidx < (size_t)source->num_lib_deps; libidx++) {
+        source_t *lib = source->lib_deps[libidx];
+        if (hash_lookup_global_or_weak_symbol(lib, symname, found_sym) != NULL)
+        {
+            sym_source = lib;
+            if (found) {
+                if (found == 1) {
+                    found++;
+                    ERROR("ERROR: multiple definitions found for [%s:%s]!\n",
+                          source->name, symname);
+                    ERROR("\tthis definition     [%s]\n", lib->name);
+                }
+                ERROR("\tprevious definition [%s]\n", last_found->name);
+            }
+            last_found = lib;
+            if (!found) found = 1;
+        }
+    }
+
+#if ELF_STRPTR_IS_BROKEN
+    ASSERT(!sym_source ||
+           !strcmp(symname,
+                   (char *)(elf_getdata(elf_getscn(
+                                            sym_source->elf,
+                                            sym_source->symtab.shdr.sh_link),
+                                        NULL)->d_buf) +
+                   found_sym->st_name));
+#else
+    ASSERT(!sym_source ||
+           !strcmp(symname,
+                   elf_strptr(sym_source->elf,
+                              sym_source->symtab.shdr.sh_link,
+                              found_sym->st_name)));
+#endif
+
+    return sym_source;
+}
+
+static int do_prelink(source_t *source,
+                      Elf_Data *reloc_scn_data,
+                      int reloc_scn_entry_size,
+                      unfinished_relocation_t *unfinished,
+                      int locals_only,
+                      bool dry_run,
+                      char **lib_lookup_dirs, int num_lib_lookup_dirs,
+                      char **default_libs, int num_default_libs,
+                      int *num_unfinished_relocs)
+{
+    int num_relocations = 0;
+
+    size_t num_rels;
+    num_rels = reloc_scn_data->d_size / reloc_scn_entry_size;
+
+    INFO("\tThere are %d relocations.\n", num_rels);
+
+    int rel_idx;
+    for (rel_idx = 0; rel_idx < (size_t)num_rels; rel_idx++) {
+        GElf_Rel *rel, rel_mem;
+
+        //INFO("\tHandling relocation %d/%d\n", rel_idx, num_rels);
+
+        rel = gelf_getrel(reloc_scn_data, rel_idx, &rel_mem);
+        FAILIF_LIBELF(rel == NULL, gelf_getrel);
+        GElf_Sym *sym = NULL, sym_mem;
+        unsigned sym_idx = GELF_R_SYM(rel->r_info);
+        source_t *sym_source = NULL;
+        /* found_sym points to found_sym_mem, when sym_source != NULL, and
+           to sym, when the sybmol is locally defined.  If the symbol is
+           not locally defined and sym_source == NULL, then sym is not
+           defined either. */
+        GElf_Sym *found_sym = NULL, found_sym_mem;
+        const char *symname = NULL;
+        int sym_is_local = 1;
+        if (sym_idx) {
+          sym = gelf_getsymshndx(source->symtab.data,
+                                 NULL,
+                                 sym_idx,
+                                 &sym_mem,
+                                 NULL);
+          FAILIF_LIBELF(NULL == sym, gelf_getsymshndx);
+#if ELF_STRPTR_IS_BROKEN
+          symname =
+              ((char *)source->strtab.data->d_buf) +
+              sym->st_name;
+#else
+          symname = elf_strptr(source->elf,
+                               elf_ndxscn(source->strtab.scn),
+                               sym->st_name);
+#endif
+
+          /* If the symbol is defined and is either not in the BSS
+             section, or if it is in the BSS then the relocation is
+             not a copy relocation, then the symbol's source is this
+             library (i.e., it is locally-defined).  Otherwise, the
+             symbol is imported.
+          */
+
+          sym_is_local = 0;
+          if (sym->st_shndx != SHN_UNDEF &&
+              (source->bss.scn == NULL ||
+               sym->st_shndx != elf_ndxscn(source->bss.scn) ||
+#ifdef ARM_SPECIFIC_HACKS
+               GELF_R_TYPE(rel->r_info) != R_ARM_COPY
+#else
+               1
+#endif
+               ))
+            {
+              sym_is_local = 1;
+            }
+
+          if (sym_is_local) {
+            INFO("\t\tSymbol [%s:%s] is defined locally.\n",
+                 source->name,
+                 symname);
+            sym_source = source;
+            found_sym = sym;
+          }
+          else if (!locals_only) {
+            sym_source = lookup_symbol_in_dependencies(source,
+                                                       symname,
+                                                       &found_sym_mem);
+
+            /* The symbol was not in the list of dependencies, which by
+               itself is an error:  it means either that the symbol does
+               not exist anywhere, or that the library which has the symbol
+               has not been listed as a dependency in this library or
+               executable. It could also mean (for a library) that the
+               symbol is defined in the executable that links agsinst it,
+               which is obviously not a good thing.  These are bad things,
+               but they do happen, which is why we have the ability to
+               provide a list of default dependencies, including
+               executables. Here we check to see if the symbol has been
+               defined in any of them.
+            */
+            if (NULL == sym_source) {
+              INFO("\t\tChecking default dependencies...\n");
+              int i;
+              source_t *lib, *old_sym_source = NULL;
+              int printed_initial_error = 0;
+              for (i = 0; i < num_default_libs; i++) {
+                INFO("\tChecking in [%s].\n", default_libs[i]);
+                lib = find_source(default_libs[i],
+                                  lib_lookup_dirs,
+                                  num_lib_lookup_dirs);
+                FAILIF(NULL == lib,
+                       "Can't find default library [%s]!\n",
+                       default_libs[i]);
+                if (hash_lookup_global_or_weak_symbol(lib,
+                                                      symname,
+                                                      &found_sym_mem)) {
+                  found_sym = &found_sym_mem;
+                  sym_source = lib;
+#if ELF_STRPTR_IS_BROKEN
+                  ASSERT(!strcmp(symname,
+                                 (char *)(elf_getdata(
+                                              elf_getscn(
+                                                  sym_source->elf,
+                                                  sym_source->symtab.
+                                                      shdr.sh_link),
+                                              NULL)->d_buf) +
+                                 found_sym->st_name));
+#else
+                  ASSERT(!strcmp(symname,
+                                 elf_strptr(sym_source->elf,
+                                            sym_source->symtab.shdr.sh_link,
+                                            found_sym->st_name)));
+
+#endif
+                  INFO("\tFound symbol [%s] in [%s]!\n",
+                       symname, lib->name);
+                  if (old_sym_source) {
+                    if (printed_initial_error == 0) {
+                      printed_initial_error = 1;
+                      ERROR("Multiple definition of [%s]:\n"
+                            "\t[%s]\n",
+                            symname,
+                            old_sym_source->name);
+                    }
+                    ERROR("\t[%s]\n", sym_source->name);
+                  }
+                  old_sym_source = sym_source;
+                } else {
+                  INFO("\tCould not find symbol [%s] in default "
+                       "lib [%s]!\n", symname, lib->name);
+                }
+              }
+              if (sym_source) {
+                ERROR("ERROR: Could not find [%s:%s] in dependent "
+                      "libraries (but found in default [%s])!\n",
+                      source->name,
+                      symname,
+                      sym_source->name);
+              }
+            } else {
+              found_sym = &found_sym_mem;
+              /* We found the symbol in a dependency library. */
+              INFO("\t\tSymbol [%s:%s, value %lld] is imported from [%s]\n",
+                   source->name,
+                   symname,
+                   found_sym->st_value,
+                   sym_source->name);
+            }
+          } /* if symbol is defined in this library... */
+
+          if (!locals_only) {
+            /* If a symbol is weak and we haven't found it, then report
+               an error.  We really need to find a way to set its value
+               to zero.  The problem is that it needs to refer to some
+               section. */
+
+            FAILIF(NULL == sym_source &&
+                   GELF_ST_BIND(sym->st_info) == STB_WEAK,
+                   "Cannot handle weak symbols yet (%s:%s <- %s).\n",
+                   source->name,
+                   symname,
+                   sym_source->name);
+#ifdef PERMISSIVE
+            if (GELF_ST_BIND(sym->st_info) != STB_WEAK &&
+                NULL == sym_source) {
+              ERROR("ERROR: Can't find symbol [%s:%s] in dependent or "
+                    "default libraries!\n", source->name, symname);
+            }
+#else
+            FAILIF(GELF_ST_BIND(sym->st_info) != STB_WEAK &&
+                   NULL == sym_source,
+                   "Can't find symbol [%s:%s] in dependent or default "
+                   "libraries!\n",
+                   source->name,
+                   symname);
+#endif
+          } /* if (!locals_only) */
+        }
+#if 0 // too chatty
+        else
+          INFO("\t\tno symbol is associated with this relocation\n");
+#endif
+
+
+        // We prelink only local symbols when locals_only == 1.
+
+        bool can_relocate = true;
+        if (!sym_is_local &&
+            (symname[0] == 'd' && symname[1] == 'l' && symname[2] != '\0' &&
+             (!strcmp(symname + 2, "open") ||
+              !strcmp(symname + 2, "close") ||
+              !strcmp(symname + 2, "sym") ||
+              !strcmp(symname + 2, "error")))) {
+            INFO("********* NOT RELOCATING LIBDL SYMBOL [%s]\n", symname);
+            can_relocate = false;
+        }
+
+        if (can_relocate && (sym_is_local || !locals_only))
+        {
+            GElf_Shdr shdr_mem; Elf_Scn *scn; Elf_Data *data;
+            find_section(source, rel->r_offset, &scn, &shdr_mem, &data);
+            unsigned *dest =
+              (unsigned*)(((char *)data->d_buf) +
+                          (rel->r_offset - shdr_mem.sh_addr));
+            unsigned rel_type = GELF_R_TYPE(rel->r_info);
+            char buf[64];
+            INFO("\t\t%-15s ",
+                 ebl_reloc_type_name(source->ebl,
+                                     GELF_R_TYPE(rel->r_info),
+                                     buf,
+                                     sizeof(buf)));
+
+            /* Section-name offsets do not change, so we use oldelf to get the
+               strings.  This makes a difference in the second pass of the
+               perlinker, after the call to adjust_elf, because
+               source->shstrndx no longer contains the index of the
+               section-header-strings table.
+            */
+            const char *sname = elf_strptr(
+                source->oldelf, source->shstrndx, shdr_mem.sh_name);
+
+            switch (rel_type) {
+            case R_ARM_JUMP_SLOT:
+            case R_ARM_GLOB_DAT:
+            case R_ARM_ABS32:
+              ASSERT(data->d_buf != NULL);
+              ASSERT(data->d_size >= rel->r_offset - shdr_mem.sh_addr);
+#ifdef PERMISSIVE
+              if (sym_source == NULL) {
+                ERROR("ERROR: Permissive relocation "
+                      "[%-15s] [%s:%s]: [0x%llx] = ZERO\n",
+                      ebl_reloc_type_name(source->ebl,
+                                          GELF_R_TYPE(rel->r_info),
+                                          buf,
+                                          sizeof(buf)),
+                      sname,
+                      symname,
+                      rel->r_offset);
+                if (!dry_run)
+                  *dest = 0;
+              } else
+#endif
+                {
+                  ASSERT(sym_source);
+                  INFO("[%s:%s]: [0x%llx] = 0x%llx + 0x%lx\n",
+                       sname,
+                       symname,
+                       rel->r_offset,
+                       found_sym->st_value,
+                       sym_source->base);
+                  if (!dry_run)
+                    *dest = found_sym->st_value + sym_source->base;
+                }
+              num_relocations++;
+              break;
+            case R_ARM_RELATIVE:
+              ASSERT(data->d_buf != NULL);
+              ASSERT(data->d_size >= rel->r_offset - shdr_mem.sh_addr);
+              FAILIF(sym != NULL,
+                     "Unsupported RELATIVE form (symbol != 0)...\n");
+              INFO("[%s:%s]: [0x%llx] = 0x%x + 0x%lx\n",
+                   sname,
+                   symname ?: "(symbol has no name)",
+                   rel->r_offset, *dest, source->base);
+              if (!dry_run)
+                *dest += source->base;
+              num_relocations++;
+              break;
+            case R_ARM_COPY:
+#ifdef PERMISSIVE
+              if (sym_source == NULL) {
+                ERROR("ERROR: Permissive relocation "
+                      "[%-15s] [%s:%s]: NOT PERFORMING\n",
+                      ebl_reloc_type_name(source->ebl,
+                                          GELF_R_TYPE(rel->r_info),
+                                          buf,
+                                          sizeof(buf)),
+                      sname,
+                      symname);
+              } else
+#endif
+                {
+                  ASSERT(sym);
+                  ASSERT(sym_source);
+                  GElf_Shdr src_shdr_mem;
+                  Elf_Scn *src_scn;
+                  Elf_Data *src_data;
+                  find_section(sym_source, found_sym->st_value,
+                               &src_scn,
+                               &src_shdr_mem,
+                               &src_data);
+                  INFO("Found [%s:%s (%lld)] in section [%s] .\n",
+                       sym_source->name,
+                       symname,
+                       found_sym->st_value,
+#if ELF_STRPTR_IS_BROKEN
+                       (((char *)elf_getdata(
+                             elf_getscn(sym_source->elf,
+                                        sym_source->shstrndx),
+                             NULL)->d_buf) + src_shdr_mem.sh_name)
+#else
+                       elf_strptr(sym_source->elf,
+                                  sym_source->shstrndx,
+                                  src_shdr_mem.sh_name)
+#endif
+                      );
+
+                  unsigned *src = NULL;
+                  if (src_data->d_buf == NULL)
+                    {
+#ifdef PERMISSIVE
+                      if (sym_source->bss.scn == NULL ||
+                          elf_ndxscn(src_scn) !=
+                          elf_ndxscn(sym_source->bss.scn)) {
+                        ERROR("ERROR: Permissive relocation (NULL source "
+                              "not from .bss) [%-15s] [%s:%s]: "
+                              "NOT PERFORMING\n",
+                              ebl_reloc_type_name(source->ebl,
+                                                  GELF_R_TYPE(rel->r_info),
+                                                  buf,
+                                                  sizeof(buf)),
+                              sname,
+                              symname);
+                      }
+#endif
+                    }
+                  else {
+                    ASSERT(src_data->d_size >=
+                           found_sym->st_value - src_shdr_mem.sh_addr);
+                    src = (unsigned*)(((char *)src_data->d_buf) +
+                                      (found_sym->st_value -
+                                       src_shdr_mem.sh_addr));
+                  }
+                  ASSERT(symname);
+                  INFO("[%s:%s]: [0x%llx] <- [0x%llx] size %lld\n",
+                       sname,
+                       symname, rel->r_offset,
+                       found_sym->st_value,
+                       found_sym->st_size);
+
+#ifdef PERMISSIVE
+                  if (src_data->d_buf != NULL ||
+                      (sym_source->bss.scn != NULL &&
+                       elf_ndxscn(src_scn) ==
+                       elf_ndxscn(sym_source->bss.scn)))
+#endif/*PERMISSIVE*/
+                    {
+                      if (data->d_buf == NULL) {
+                        INFO("Incomplete relocation [%-15s] of [%s:%s].\n",
+                             ebl_reloc_type_name(source->ebl,
+                                                 GELF_R_TYPE(rel->r_info),
+                                                 buf,
+                                                 sizeof(buf)),
+                             sname,
+                             symname);
+                        FAILIF(unfinished == NULL,
+                               "You passed unfinished as NULL expecting "
+                               "to handle all relocations, "
+                               "but at least one cannot be handled!\n");
+                        if (unfinished->num_rels == unfinished->rels_size) {
+                          unfinished->rels_size += 10;
+                          unfinished->rels = (GElf_Rel *)REALLOC(
+                              unfinished->rels,
+                              unfinished->rels_size *
+                              sizeof(GElf_Rel));
+                        }
+                        unfinished->rels[unfinished->num_rels++] = *rel;
+                        num_relocations--;
+                        (*num_unfinished_relocs)++;
+                      }
+                      else {
+                        if (src_data->d_buf != NULL)
+                          {
+                            ASSERT(data->d_buf != NULL);
+                            ASSERT(data->d_size >= rel->r_offset -
+                                   shdr_mem.sh_addr);
+                            if (!dry_run)
+                              memcpy(dest, src, found_sym->st_size);
+                          }
+                        else {
+                          ASSERT(src == NULL);
+                          ASSERT(elf_ndxscn(src_scn) ==
+                                 elf_ndxscn(sym_source->bss.scn));
+                          if (!dry_run)
+                            memset(dest, 0, found_sym->st_size);
+                        }
+                      }
+                    }
+                  num_relocations++;
+                }
+              break;
+            default:
+              FAILIF(1, "Unknown relocation type %d!\n", rel_type);
+            } // switch
+        } // relocate
+        else {
+          INFO("\t\tNot relocating symbol [%s]%s\n",
+               symname,
+               (can_relocate ? ", relocating only locals" : 
+                ", which is a libdl symbol"));
+          FAILIF(unfinished == NULL,
+                 "You passed unfinished as NULL expecting to handle all "
+                 "relocations, but at least one cannot be handled!\n");
+          if (unfinished->num_rels == unfinished->rels_size) {
+              unfinished->rels_size += 10;
+              unfinished->rels = (GElf_Rel *)REALLOC(
+                  unfinished->rels,
+                  unfinished->rels_size *
+                  sizeof(GElf_Rel));
+          }
+          unfinished->rels[unfinished->num_rels++] = *rel;
+          (*num_unfinished_relocs)++;
+        }
+    } // for each relocation entry
+
+    return num_relocations;
+}
+
+static int prelink(source_t *source,
+                   int locals_only,
+                   bool dry_run,
+                   char **lib_lookup_dirs, int num_lib_lookup_dirs,
+                   char **default_libs, int num_default_libs,
+                   int *num_unfinished_relocs)
+{
+    INFO("Prelinking [%s] (number of relocation sections: %d)%s...\n",
+         source->name, source->num_relocation_sections,
+         (dry_run ? " (dry run)" : ""));
+    int num_relocations = 0;
+    int rel_scn_idx;
+    for (rel_scn_idx = 0; rel_scn_idx < source->num_relocation_sections;
+         rel_scn_idx++)
+    {
+        section_info_t *reloc_scn = source->relocation_sections + rel_scn_idx;
+        unfinished_relocation_t *unfinished = source->unfinished + rel_scn_idx;
+
+        /* We haven't modified the shstrtab section, and so shdr->sh_name has
+           the same value as before.  Thus we look up the name based on the old
+           ELF handle.  We cannot use shstrndx on the new ELF handle because
+           the index of the shstrtab section may have changed (and calling
+           elf_getshstrndx() returns the same section index, so libelf can't
+           handle thise ither).
+
+           If reloc_scn->info is available, we can assert that the
+           section-name has not changed.  If this assertion fails,
+           then we cannot use the elf_strptr() trick below to get
+           the section name.  One solution would be to save it in
+           the section_info_t structure.
+        */
+        ASSERT(reloc_scn->info == NULL ||
+               reloc_scn->shdr.sh_name == reloc_scn->info->old_shdr.sh_name);
+        const char *sname =
+          elf_strptr(source->oldelf,
+                     source->shstrndx,
+                     reloc_scn->shdr.sh_name);
+        ASSERT(sname != NULL);
+
+        INFO("\n\tIterating relocation section [%s]...\n", sname);
+
+        /* In general, the new size of the section differs from the original
+           size of the section, because we can handle some of the relocations.
+           This was communicated to adjust_elf, which modified the ELF file
+           according to the new section sizes.  Now, when prelink() does the
+           actual work of prelinking, it needs to know the original size of the
+           relocation section so that it can see all of the original relocation
+           entries!
+        */
+        size_t d_size = reloc_scn->data->d_size;
+        if (reloc_scn->info != NULL &&
+            reloc_scn->data->d_size != reloc_scn->info->old_shdr.sh_size)
+        {
+            INFO("Setting size of section [%s] to from new size %d to old "
+                 "size %lld temporarily (so prelinker can see all "
+                 "relocations).\n",
+                 reloc_scn->info->name,
+                 d_size,
+                 reloc_scn->info->old_shdr.sh_size);
+            reloc_scn->data->d_size = reloc_scn->info->old_shdr.sh_size;
+        }
+
+        num_relocations +=
+          do_prelink(source,
+                     reloc_scn->data, reloc_scn->shdr.sh_entsize,
+                     unfinished,
+                     locals_only, dry_run,
+                     lib_lookup_dirs, num_lib_lookup_dirs,
+                     default_libs, num_default_libs,
+                     num_unfinished_relocs);
+
+        if (reloc_scn->data->d_size != d_size)
+        {
+            ASSERT(reloc_scn->info != NULL);
+            INFO("Resetting size of section [%s] to %d\n",
+                 reloc_scn->info->name,
+                 d_size);
+            reloc_scn->data->d_size = d_size;
+        }
+    }
+
+    /* Now prelink those relocation sections which were fully handled, and
+       therefore removed.  They are not a part of the
+       source->relocation_sections[] array anymore, but we can find them by
+       scanning source->shdr_info[] and looking for sections with idx == 0.
+    */
+
+    if (ADJUST_ELF && source->shdr_info != NULL) {
+        /* Walk over the shdr_info[] array to see if we've removed any
+           relocation sections.  prelink() those sections as well.
+        */
+        int i;
+        for (i = 0; i < source->shnum; i++) {
+            shdr_info_t *info = source->shdr_info + i;
+            if (info->idx == 0 &&
+                (info->shdr.sh_type == SHT_REL ||
+                 info->shdr.sh_type == SHT_RELA)) {
+
+              Elf_Data *data = elf_getdata(info->scn, NULL);
+              ASSERT(data->d_size == 0);
+              data->d_size = info->old_shdr.sh_size;
+
+              INFO("\n\tIterating relocation section [%s], which was "
+                   "discarded (size %d, entry size %lld).\n",
+                   info->name,
+                   data->d_size,
+                   info->old_shdr.sh_entsize);
+
+              num_relocations +=
+                do_prelink(source,
+                           data, info->old_shdr.sh_entsize,
+                           NULL, /* the section was fully handled */
+                           locals_only, dry_run,
+                           lib_lookup_dirs, num_lib_lookup_dirs,
+                           default_libs, num_default_libs,
+                           num_unfinished_relocs);
+
+              data->d_size = 0;
+            }
+        }
+    }
+    return num_relocations;
+}
+
+static char * find_file(const char *libname,
+                        char **lib_lookup_dirs,
+                        int num_lib_lookup_dirs) {
+    if (libname[0] == '/') {
+        /* This is an absolute path name--just return it. */
+        /* INFO("ABSOLUTE PATH: [%s].\n", libname); */
+        return strdup(libname);
+    } else {
+        /* First try the working directory. */
+        int fd;
+        if ((fd = open(libname, O_RDONLY)) > 0) {
+            close(fd);
+            /* INFO("FOUND IN CURRENT DIR: [%s].\n", libname); */
+            return strdup(libname);
+        } else {
+            /* Iterate over all library paths.  For each path, append the file
+               name and see if there is a file at that place. If that fails,
+               bail out. */
+
+            char *name;
+            while (num_lib_lookup_dirs--) {
+                size_t lib_len = strlen(*lib_lookup_dirs);
+                /* one extra character for the slash, and another for the
+                   terminating NULL. */
+                name = (char *)MALLOC(lib_len + strlen(libname) + 2);
+                strcpy(name, *lib_lookup_dirs);
+                name[lib_len] = '/';
+                strcpy(name + lib_len + 1, libname);
+                if ((fd = open(name, O_RDONLY)) > 0) {
+                    close(fd);
+                    /* INFO("FOUND: [%s] in [%s].\n", libname, name); */
+                    return name;
+                }
+                INFO("NOT FOUND: [%s] in [%s].\n", libname, name);
+                free(name);
+            }
+        }
+    }
+    return NULL;
+}
+
+static void adjust_dynamic_segment_entry_size(source_t *source,
+                                              dt_rel_info_t *dyn)
+{
+    /* Update the size entry in the DT_DYNAMIC segment. */
+    GElf_Dyn *dyn_entry, dyn_entry_mem;
+    dyn_entry = gelf_getdyn(source->dynamic.data,
+                            dyn->sz_idx,
+                            &dyn_entry_mem);
+    FAILIF_LIBELF(NULL == dyn_entry, gelf_getdyn);
+    /* If we are calling this function to adjust the size of the dynamic entry,
+       then there should be some unfinished relocations remaining.  If there
+       are none, then we should remove the entry from the dynamic section
+       altogether.
+    */
+    ASSERT(dyn->num_unfinished_relocs);
+
+    size_t relsize = gelf_fsize(source->elf,
+                                ELF_T_REL,
+                                1,
+                                source->elf_hdr.e_version);
+
+    if (unlikely(verbose_flag)) {
+        char buf[64];
+        INFO("Updating entry %d: [%-10s], %08llx --> %08x\n",
+             dyn->sz_idx,
+             ebl_dynamic_tag_name (source->ebl, dyn_entry->d_tag,
+                                   buf, sizeof (buf)),
+             dyn_entry->d_un.d_val,
+             dyn->num_unfinished_relocs * relsize);
+    }
+
+    dyn_entry->d_un.d_val = dyn->num_unfinished_relocs * relsize;
+
+    FAILIF_LIBELF(!gelf_update_dyn(source->dynamic.data,
+                                   dyn->sz_idx,
+                                   dyn_entry),
+                  gelf_update_dyn);
+}
+
+static void adjust_dynamic_segment_entries(source_t *source)
+{
+    /* This function many remove entries from the dynamic segment, but it won't
+       resize the relevant section.  It'll just fill the remainted with empty
+       DT entries.
+
+       FIXME: This is not guaranteed right now.  If a dynamic segment does not
+       end with null DT entries, I think this will break.
+    */
+    FAILIF(source->rel.processed,
+           "More than one section matches DT_REL entry in dynamic segment!\n");
+    FAILIF(source->jmprel.processed,
+           "More than one section matches DT_JMPREL entry in "
+           "dynamic segment!\n");
+    source->rel.processed =
+      source->jmprel.processed = 1;
+
+    if (source->rel.num_unfinished_relocs > 0)
+        adjust_dynamic_segment_entry_size(source, &source->rel);
+
+    if (source->jmprel.num_unfinished_relocs > 0)
+        adjust_dynamic_segment_entry_size(source, &source->jmprel);
+
+    /* If at least one of the entries is empty, then we need to remove it.  We
+       have already adjusted the size of the other.
+    */
+    if (source->rel.num_unfinished_relocs == 0 ||
+        source->jmprel.num_unfinished_relocs == 0)
+    {
+        /* We need to delete the DT_REL/DT_RELSZ and DT_PLTREL/DT_PLTRELSZ
+           entries from the dynamic segment. */
+
+        GElf_Dyn *dyn_entry, dyn_entry_mem;
+        size_t dynidx, updateidx;
+
+        size_t numdyn =
+            source->dynamic.shdr.sh_size /
+            source->dynamic.shdr.sh_entsize;
+
+        for (updateidx = dynidx = 0; dynidx < numdyn; dynidx++)
+        {
+            dyn_entry = gelf_getdyn(source->dynamic.data,
+                                    dynidx,
+                                    &dyn_entry_mem);
+            FAILIF_LIBELF(NULL == dyn_entry, gelf_getdyn);
+            if ((source->rel.num_unfinished_relocs == 0 &&
+                 (dynidx == source->rel.idx ||
+                  dynidx == source->rel.sz_idx)) ||
+                (source->jmprel.num_unfinished_relocs == 0 &&
+                 (dynidx == source->jmprel.idx ||
+                  dynidx == source->jmprel.sz_idx)))
+            {
+                if (unlikely(verbose_flag)) {
+                    char buf[64];
+                    INFO("\t(!)\tRemoving entry %02d: [%-10s], %08llx\n",
+                         dynidx,
+                         ebl_dynamic_tag_name (source->ebl, dyn_entry->d_tag,
+                                               buf, sizeof (buf)),
+                         dyn_entry->d_un.d_val);
+                }
+                continue;
+            }
+
+            if (unlikely(verbose_flag)) {
+                char buf[64];
+                INFO("\t\tKeeping  entry %02d: [%-10s], %08llx\n",
+                     dynidx,
+                     ebl_dynamic_tag_name (source->ebl, dyn_entry->d_tag,
+                                           buf, sizeof (buf)),
+                     dyn_entry->d_un.d_val);
+            }
+
+            gelf_update_dyn(source->dynamic.data,
+                            updateidx,
+                            &dyn_entry_mem);
+            updateidx++;
+        }
+    }
+} /* adjust_dynamic_segment_entries */
+
+static bool adjust_dynamic_segment_for(source_t *source,
+                                       dt_rel_info_t *dyn,
+                                       bool adjust_section_size_only)
+{
+    bool dropped_sections = false;
+
+    /* Go over the sections that belong to this dynamic range. */
+    dyn->num_unfinished_relocs = 0;
+    if (dyn->sections) {
+        int num_scns, idx;
+        range_t *scns = get_sorted_ranges(dyn->sections, &num_scns);
+
+        INFO("\tdynamic range %s:[%lld, %lld) contains %d sections.\n",
+             source->name,
+             dyn->addr,
+             dyn->addr + dyn->size,
+             num_scns);
+
+        ASSERT(scns);
+        int next_idx = 0, next_rel_off = 0;
+        /* The total number of unfinished relocations for this dynamic
+         * entry. */
+        section_info_t *next = (section_info_t *)scns[next_idx].user;
+        section_info_t *first = next;
+        ASSERT(first);
+        for (idx = 0; idx < num_scns; idx++) {
+            section_info_t *reloc_scn = (section_info_t *)scns[idx].user;
+            size_t rel_scn_idx = reloc_scn - source->relocation_sections;
+            ASSERT(rel_scn_idx < (size_t)source->num_relocation_sections);
+            unfinished_relocation_t *unfinished =
+                &source->unfinished[rel_scn_idx];
+            int unf_idx;
+
+            ASSERT(reloc_scn->info == NULL ||
+                   reloc_scn->shdr.sh_name ==
+                   reloc_scn->info->old_shdr.sh_name);
+            const char *sname =
+              elf_strptr(source->oldelf,
+                         source->shstrndx,
+                         reloc_scn->shdr.sh_name);
+
+            INFO("\tsection [%s] contains %d unfinished relocs.\n",
+                 sname,
+                 unfinished->num_rels);
+
+            for (unf_idx = 0; unf_idx < unfinished->num_rels; unf_idx++)
+            {
+                /* There are unfinished relocations.  Copy them forward to the
+                   lowest section we can. */
+
+                while (next_rel_off == 
+                       (int)(next->shdr.sh_size/next->shdr.sh_entsize))
+                {
+                    INFO("\tsection [%s] has filled up with %d unfinished "
+                         "relocs.\n",
+                         sname,
+                         next_rel_off);
+
+                    next_idx++;
+                    ASSERT(next_idx <= idx);
+                    next = (section_info_t *)scns[next_idx].user;
+                    next_rel_off = 0;
+                }
+
+                if (!adjust_section_size_only) {
+                    INFO("\t\tmoving unfinished relocation %2d to [%s:%d]\n",
+                         unf_idx,
+                         sname,
+                         next_rel_off);
+                    FAILIF_LIBELF(0 ==
+                                  gelf_update_rel(next->data,
+                                                  next_rel_off,
+                                                  &unfinished->rels[unf_idx]),
+                                  gelf_update_rel);
+                }
+
+                next_rel_off++;
+                dyn->num_unfinished_relocs++;
+            }
+        } /* for */
+
+        /* Set the size of the last section, and mark all subsequent
+           sections for removal.  At this point, next is the section
+           to which we last wrote data, next_rel_off is the offset before
+           which we wrote the last relocation, and so next_rel_off *
+           relsize is the new size of the section.
+        */
+
+        bool adjust_file = ADJUST_ELF && source->elf_hdr.e_type != ET_EXEC;
+        if (adjust_file && !source->dry_run)
+        {
+            size_t relsize = gelf_fsize(source->elf,
+                                        ELF_T_REL,
+                                        1,
+                                        source->elf_hdr.e_version);
+
+            ASSERT(next->info == NULL ||
+                   next->shdr.sh_name == next->info->old_shdr.sh_name);
+            const char *sname =
+              elf_strptr(source->oldelf,
+                         source->shstrndx,
+                         next->shdr.sh_name);
+
+            INFO("\tsection [%s] (index %d) has %d unfinished relocs, "
+                 "changing its size to %ld bytes (from %ld bytes).\n",
+                 sname,
+                 elf_ndxscn(next->scn),
+                 next_rel_off,
+                 (long)(next_rel_off * relsize),
+                 (long)(next->shdr.sh_size));
+
+            /* source->shdr_info[] must be allocated prior to calling this
+               function.  This is in fact done in process_file(), by calling
+               setup_shdr_info() just before we call adjust_dynamic_segment().
+            */
+            ASSERT(source->shdr_info != NULL);
+
+            /* We do not update the data field of shdr_info[], because it does
+               not exist yet (with ADJUST_ELF != 0).  We create the new section
+               and section data after the first call to prelink().  For now, we
+               save the results of our analysis by modifying the sh_size field
+               of the section header.  When we create the new sections' data,
+               we set the size of the data from the sh_size fields of the
+               section headers.
+
+               NOTE: The assertion applies only to the first call of
+                     adjust_dynamic_segment (which calls this function).  By
+                     the second call, we've already created the data for the
+                     new sections.  The only sections for which we haven't
+                     created data are the relocation sections we are removing.
+            */
+#ifdef DEBUG
+            ASSERT((!adjust_section_size_only &&
+                    (source->shdr_info[elf_ndxscn(next->scn)].idx > 0)) ||
+                   source->shdr_info[elf_ndxscn(next->scn)].data == NULL);
+#endif
+
+            //FIXME: what else do we need to do here?  Do we need to update
+            //       another copy of the shdr so that it's picked up when we
+            //       commit the file?
+            next->shdr.sh_size = next_rel_off * relsize;
+            source->shdr_info[elf_ndxscn(next->scn)].shdr.sh_size =
+                next->shdr.sh_size;
+            if (next_rel_off * relsize == 0) {
+#ifdef REMOVE_HANDLED_SECTIONS
+                INFO("\tsection [%s] (index %d) is now empty, marking for "
+                     "removal.\n",
+                     sname,
+                     elf_ndxscn(next->scn));
+                source->shdr_info[elf_ndxscn(next->scn)].idx = 0;
+                dropped_sections = true;
+#endif
+            }
+
+            while (++next_idx < num_scns) {
+                next = (section_info_t *)scns[next_idx].user;
+#ifdef REMOVE_HANDLED_SECTIONS
+                ASSERT(next->info == NULL ||
+                       next->shdr.sh_name == next->info->old_shdr.sh_name);
+                const char *sname =
+                  elf_strptr(source->oldelf,
+                             source->shstrndx,
+                             next->shdr.sh_name);
+                INFO("\tsection [%s] (index %d) is now empty, marking for "
+                     "removal.\n",
+                     sname,
+                     elf_ndxscn(next->scn));
+                /* mark for removal */
+                source->shdr_info[elf_ndxscn(next->scn)].idx = 0;
+                dropped_sections = true;
+#endif
+            }
+        }
+
+    } /* if (dyn->sections) */
+    else {
+        /* The dynamic entry won't have any sections when it itself doesn't
+           exist.  This could happen when we remove all relocation sections
+           from a dynamic entry because we have managed to handle all
+           relocations in them.
+        */
+        INFO("\tNo section for dynamic entry!\n");
+    }
+
+    return dropped_sections;
+}
+
+static bool adjust_dynamic_segment(source_t *source,
+                                   bool adjust_section_size_only)
+{
+    bool dropped_section;
+    INFO("Adjusting dynamic segment%s.\n",
+         (adjust_section_size_only ? " (section sizes only)" : ""));
+    INFO("\tadjusting dynamic segment REL.\n");
+    dropped_section =
+        adjust_dynamic_segment_for(source, &source->rel,
+                                   adjust_section_size_only);
+    INFO("\tadjusting dynamic segment JMPREL.\n");
+    dropped_section =
+        adjust_dynamic_segment_for(source, &source->jmprel,
+                                   adjust_section_size_only) ||
+        dropped_section;
+    if (!adjust_section_size_only)
+        adjust_dynamic_segment_entries(source);
+    return dropped_section;
+}
+
+static void match_relocation_sections_to_dynamic_ranges(source_t *source)
+{
+    /* We've gathered all the DT_DYNAMIC entries; now we need to figure out
+       which relocation sections fit in which range as described by the
+       entries.
+    */
+
+    int relidx;
+    for (relidx = 0; relidx < source->num_relocation_sections; relidx++) {
+        section_info_t *reloc_scn = &source->relocation_sections[relidx];
+
+        int index = elf_ndxscn(reloc_scn->scn);
+
+        ASSERT(reloc_scn->info == NULL ||
+               reloc_scn->shdr.sh_name == reloc_scn->info->old_shdr.sh_name);
+        const char *sname =
+          elf_strptr(source->oldelf,
+                     source->shstrndx,
+                     reloc_scn->shdr.sh_name);
+
+        INFO("Checking section [%s], index %d, for match to dynamic ranges\n",
+             sname, index);
+        if (source->shdr_info == NULL || reloc_scn->info->idx > 0) {
+            if (source->rel.addr &&
+                source->rel.addr <= reloc_scn->shdr.sh_addr &&
+                reloc_scn->shdr.sh_addr < source->rel.addr + source->rel.size)
+                {
+                    /* The entire section must fit in the dynamic range. */
+                    if((reloc_scn->shdr.sh_addr + reloc_scn->shdr.sh_size) >
+                       (source->rel.addr + source->rel.size))
+                        {
+                            PRINT("WARNING: In [%s], section %s:[%lld,%lld) "
+                                  "is not fully contained in dynamic range "
+                                  "[%lld,%lld)!\n",
+                                  source->name,
+                                  sname,
+                                  reloc_scn->shdr.sh_addr,
+                                  reloc_scn->shdr.sh_addr +
+                                      reloc_scn->shdr.sh_size,
+                                  source->rel.addr,
+                                  source->rel.addr + source->rel.size);
+                        }
+
+                    if (NULL == source->rel.sections) {
+                        source->rel.sections = init_range_list();
+                        ASSERT(source->rel.sections);
+                    }
+                    add_unique_range_nosort(source->rel.sections,
+                                            reloc_scn->shdr.sh_addr,
+                                            reloc_scn->shdr.sh_size,
+                                            reloc_scn,
+                                            NULL,
+                                            NULL);
+                    INFO("\tSection [%s] matches dynamic range REL.\n",
+                         sname);
+                }
+            else if (source->jmprel.addr &&
+                     source->jmprel.addr <= reloc_scn->shdr.sh_addr &&
+                     reloc_scn->shdr.sh_addr <= source->jmprel.addr +
+                     source->jmprel.size)
+                {
+                    if((reloc_scn->shdr.sh_addr + reloc_scn->shdr.sh_size) >
+                       (source->jmprel.addr + source->jmprel.size))
+                        {
+                            PRINT("WARNING: In [%s], section %s:[%lld,%lld) "
+                                  "is not fully "
+                                  "contained in dynamic range [%lld,%lld)!\n",
+                                  source->name,
+                                  sname,
+                                  reloc_scn->shdr.sh_addr,
+                                  reloc_scn->shdr.sh_addr +
+                                      reloc_scn->shdr.sh_size,
+                                  source->jmprel.addr,
+                                  source->jmprel.addr + source->jmprel.size);
+                        }
+
+                    if (NULL == source->jmprel.sections) {
+                        source->jmprel.sections = init_range_list();
+                        ASSERT(source->jmprel.sections);
+                    }
+                    add_unique_range_nosort(source->jmprel.sections,
+                                            reloc_scn->shdr.sh_addr,
+                                            reloc_scn->shdr.sh_size,
+                                            reloc_scn,
+                                            NULL,
+                                            NULL);
+                    INFO("\tSection [%s] matches dynamic range JMPREL.\n",
+                         sname);
+                }
+            else
+                PRINT("WARNING: Relocation section [%s:%s] does not match "
+                      "any DT_ entry.\n",
+                      source->name,
+                      sname);
+        }
+        else {
+            INFO("Section [%s] was removed, not matching it to dynamic "
+                 "ranges.\n",
+                 sname);
+        }
+    } /* for ... */
+
+    if (source->rel.sections) sort_ranges(source->rel.sections);
+    if (source->jmprel.sections) sort_ranges(source->jmprel.sections);
+}
+
+static void drop_sections(source_t *source)
+{
+    INFO("We are dropping some sections from [%s]--creating section entries "
+         "only for remaining sections.\n",
+         source->name);
+    /* Renumber the sections.  The numbers for the sections after those we are
+       dropping will be shifted back by the number of dropped sections. */
+    int cnt, idx;
+    for (cnt = idx = 1; cnt < source->shnum; ++cnt) {
+        if (source->shdr_info[cnt].idx > 0) {
+            source->shdr_info[cnt].idx = idx++;
+            
+            /* Create a new section. */
+            FAILIF_LIBELF((source->shdr_info[cnt].newscn =
+                           elf_newscn(source->elf)) == NULL, elf_newscn);
+            ASSERT(elf_ndxscn (source->shdr_info[cnt].newscn) ==
+                   source->shdr_info[cnt].idx);
+            
+            /* Copy the section data */
+            Elf_Data *olddata =
+                elf_getdata(source->shdr_info[cnt].scn, // old section
+                            NULL);
+            FAILIF_LIBELF(NULL == olddata, elf_getdata);
+            Elf_Data *data = 
+                elf_newdata(source->shdr_info[cnt].newscn);
+            FAILIF_LIBELF(NULL == data, elf_newdata);
+            *data = *olddata;
+#if COPY_SECTION_DATA_BUFFER
+            if (olddata->d_buf != NULL) {
+                data->d_buf = MALLOC(data->d_size);
+                memcpy(data->d_buf, olddata->d_buf, olddata->d_size);
+            }
+#endif
+            source->shdr_info[cnt].data = data;
+            
+            if (data->d_size !=
+                source->shdr_info[cnt].shdr.sh_size) {
+                INFO("Trimming new-section data from %d to %lld bytes "
+                     "(as calculated by adjust_dynamic_segment()).\n",
+                     data->d_size,
+                     source->shdr_info[cnt].shdr.sh_size);
+                data->d_size =
+                    source->shdr_info[cnt].shdr.sh_size;
+            }
+            
+            INFO("\tsection [%s] (old offset %lld, old size %lld) "
+                 "will have index %d (was %d), new size %d\n",
+                 source->shdr_info[cnt].name,
+                 source->shdr_info[cnt].old_shdr.sh_offset,
+                 source->shdr_info[cnt].old_shdr.sh_size,
+                 source->shdr_info[cnt].idx,
+                 elf_ndxscn(source->shdr_info[cnt].scn),
+                 data->d_size);
+        } else {
+            INFO("\tIgnoring section [%s] (offset %lld, size %lld, index %d), "
+                 "it will be discarded.\n",
+                 source->shdr_info[cnt].name,
+                 source->shdr_info[cnt].shdr.sh_offset,
+                 source->shdr_info[cnt].shdr.sh_size,
+                 elf_ndxscn(source->shdr_info[cnt].scn));
+        }
+
+        /* NOTE: We mark use_old_shdr_for_relocation_calculations even for the
+           sections we are removing.  adjust_elf has an assertion that makes
+           sure that if the values for the size of a section according to its
+           header and its data structure differ, then we are using explicitly
+           the old section header for calculations, and that the section in
+           question is a relocation section.
+        */
+        source->shdr_info[cnt].use_old_shdr_for_relocation_calculations = true;
+    } /* for */
+}
+
+static source_t* process_file(const char *filename,
+                              const char *output, int is_file,
+                              void (*report_library_size_in_memory)(
+                                  const char *name, off_t fsize),
+                              unsigned (*get_next_link_address)(
+                                  const char *name),
+                              int locals_only,
+                              char **lib_lookup_dirs,
+                              int num_lib_lookup_dirs,
+                              char **default_libs,
+                              int num_default_libs,
+                              int dry_run,
+                              int *total_num_handled_relocs,
+                              int *total_num_unhandled_relocs)
+{
+    /* Look up the file in the list of already-handles files, which are
+       represented by source_t structs.  If we do not find the file, then we
+       haven't prelinked it yet.  If we find it, then we have, so we do
+       nothing.  Keep in mind that apriori operates on an entire collection
+       of files, and if application A used library L, and so does application
+       B, if we process A first, then by the time we get to B we will have
+       prelinked L already; that's why we check first to see if a library has
+       been prelinked.
+    */
+    source_t *source =
+        find_source(filename, lib_lookup_dirs, num_lib_lookup_dirs);
+    if (NULL == source) {
+        /* If we could not find the source, then it hasn't been processed yet,
+           so we go ahead and process it! */
+        INFO("Processing [%s].\n", filename);
+        char *full = find_file(filename, lib_lookup_dirs, num_lib_lookup_dirs);
+        FAILIF(NULL == full,
+               "Could not find [%s] in the current directory or in any of "
+               "the search paths!\n", filename);
+
+        unsigned base = get_next_link_address(full);
+
+        source = init_source(full, output, is_file, base, dry_run);
+
+        if (source == NULL) {
+            INFO("File [%s] is a static executable.\n", filename);
+            return NULL;
+        }
+               ASSERT(source->dynamic.scn != NULL);
+
+        /* We need to increment the next prelink address only when the file we
+           are currently handing is a shared library.  Executables do not need
+           to be prelinked at a different address, they are always at address
+           zero.
+
+           Also, if we are prelinking locals only, then we are handling a
+           single file per invokation of apriori, so there is no need to
+           increment the prelink address unless there is a global prelink map,
+           in which case we do need to check to see if the library isn't
+           running into its neighbouts in the prelink map.
+        */
+        if (source->oldelf_hdr.e_type != ET_EXEC && 
+            (!locals_only ||
+             report_library_size_in_memory == 
+             pm_report_library_size_in_memory)) {
+            /* This sets the next link address only if an increment was not
+               specified by the user.  If an address increment was specified,
+               then we just check to make sure that the file size is less than
+               the increment.
+
+               NOTE: The file size is the absolute highest number of bytes that
+               the file may occupy in memory, if the entire file is loaded, but
+               this is almost next the case.  A file will often have sections
+               which are not loaded, which could add a lot of size.  That's why
+               we start off with the file size and then subtract the size of
+               the biggest sections that will not get loaded, which are the
+               varios DWARF sections, all of which of which are named starting
+               with ".debug_".
+
+               We could do better than this (by caculating exactly how many
+               bytes from that file will be loaded), but that's an overkill.
+               Unless the prelink-address increment becomes too small, the file
+               size after subtracting the sizes of the DWARF section will be a
+               good-enough upper bound.
+            */
+
+            unsigned long fsize = source->elf_file_info.st_size;
+            INFO("Calculating loadable file size for next link address.  "
+                 "Starting with %ld.\n", fsize);
+            if (true) {
+                Elf_Scn *scn = NULL;
+                GElf_Shdr shdr_mem, *shdr;
+                const char *scn_name;
+                while ((scn = elf_nextscn (source->oldelf, scn)) != NULL) {
+                    shdr = gelf_getshdr(scn, &shdr_mem);
+                    FAILIF_LIBELF(NULL == shdr, gelf_getshdr);
+                    scn_name = elf_strptr (source->oldelf,
+                                           source->shstrndx, shdr->sh_name);
+                    ASSERT(scn_name != NULL);
+
+                    if (!(shdr->sh_flags & SHF_ALLOC)) {
+                        INFO("\tDecrementing by %lld on account of section "
+                             "[%s].\n",
+                             shdr->sh_size,
+                             scn_name);
+                        fsize -= shdr->sh_size;
+                    }                    
+                }
+            }
+            INFO("Done calculating loadable file size for next link address: "
+                 "Final value is %ld.\n", fsize);
+            report_library_size_in_memory(source->name, fsize);
+        }
+
+        /* Identify the dynamic segment and process it.  Specifically, we find
+           out what dependencies, if any, this file has.  Whenever we encounter
+           such a dependency, we process it recursively; we find out where the
+           various relocation information sections are stored. */
+
+        size_t dynidx;
+        GElf_Dyn *dyn, dyn_mem;
+        size_t numdyn =
+            source->dynamic.shdr.sh_size /
+            source->dynamic.shdr.sh_entsize;
+        ASSERT(source->dynamic.shdr.sh_size == source->dynamic.data->d_size);
+
+        source->rel.idx = source->rel.sz_idx = -1;
+        source->jmprel.idx = source->jmprel.sz_idx = -1;
+
+        for (dynidx = 0; dynidx < numdyn; dynidx++) {
+            dyn = gelf_getdyn (source->dynamic.data,
+                               dynidx,
+                               &dyn_mem);
+            FAILIF_LIBELF(NULL == dyn, gelf_getdyn);
+            /* When we are processing only the local relocations in a file,
+               we don't need to handle any of the dependencies.  It won't
+               hurt if we do, but we will be doing unnecessary work.
+            */
+            switch (dyn->d_tag)
+            {
+            case DT_NEEDED:
+                if (!locals_only) {
+                    /* Process the needed library recursively.
+                     */
+                    const char *dep_lib =
+#if ELF_STRPTR_IS_BROKEN
+                        (((char *)elf_getdata(
+                            elf_getscn(source->elf,
+                                       source->dynamic.shdr.sh_link),
+                            NULL)->d_buf) + dyn->d_un.d_val);
+#else
+                    elf_strptr (source->elf,
+                                source->dynamic.shdr.sh_link,
+                                dyn->d_un.d_val);
+#endif
+                    ASSERT(dep_lib != NULL);
+                    INFO("[%s] depends on [%s].\n", filename, dep_lib);
+                    ASSERT(output == NULL || is_file == 0);
+                    source_t *dep = process_file(dep_lib,
+                                                 output, is_file,
+                                                 report_library_size_in_memory,
+                                                 get_next_link_address,
+                                                 locals_only,
+                                                 lib_lookup_dirs,
+                                                 num_lib_lookup_dirs,
+                                                 default_libs,
+                                                 num_default_libs,
+                                                 dry_run,
+                                                 total_num_handled_relocs,
+                                                 total_num_unhandled_relocs);
+
+                    /* Add the library to the dependency list. */
+                    if (source->num_lib_deps == source->lib_deps_size) {
+                        source->lib_deps_size += 10;
+                        source->lib_deps = REALLOC(source->lib_deps,
+                                                   source->lib_deps_size *
+                                                   sizeof(source_t *));
+                    }
+                    source->lib_deps[source->num_lib_deps++] = dep;
+                }
+                break;
+            case DT_JMPREL:
+                source->jmprel.idx = dynidx;
+                source->jmprel.addr = dyn->d_un.d_ptr;
+                break;
+            case DT_PLTRELSZ:
+                source->jmprel.sz_idx = dynidx;
+                source->jmprel.size = dyn->d_un.d_val;
+                break;
+            case DT_REL:
+                source->rel.idx = dynidx;
+                source->rel.addr = dyn->d_un.d_ptr;
+                break;
+            case DT_RELSZ:
+                source->rel.sz_idx = dynidx;
+                source->rel.size = dyn->d_un.d_val;
+                break;
+            case DT_RELA:
+            case DT_RELASZ:
+                FAILIF(1, "Can't handle DT_RELA and DT_RELASZ entries!\n");
+                break;
+            } /* switch */
+        } /* for each dynamic entry... */
+
+        INFO("Handling [%s].\n", filename);
+
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+        if (!source->prelinked)
+#endif
+               {
+            /* When ADJUST_ELF is defined, this call to prelink is a dry run
+               intended to calculate the number of relocations that could not
+               be handled.  This, in turn, allows us to calculate the amount by
+               which we can shrink the various relocation sections before we
+               call adjust_elf.  After we've adjusted the sections, we will
+               call prelink() one more time to do the actual work.
+
+               NOTE: Even when ADJUST_ELF != 0, we cannot adjust an ELF file
+               that is an executabe, because an executable is not PIC.
+            */
+
+            int num_unfinished_relocs = 0;
+            bool adjust_file = ADJUST_ELF && source->elf_hdr.e_type != ET_EXEC;
+            INFO("\n\n\tPRELINKING %s\n\n",
+                 adjust_file ?
+                 "(CALCULATE NUMBER OF HANDLED RELOCATIONS)" :
+                 "(ACTUAL)");
+            int num_relocs = prelink(source, locals_only,
+                                     adjust_file || dry_run,
+                                     lib_lookup_dirs, num_lib_lookup_dirs,
+                                     default_libs, num_default_libs,
+                                     &num_unfinished_relocs);
+            INFO("[%s]: (calculate changes) handled %d, could not handle %d "
+                 "relocations.\n",
+                 source->name,
+                 num_relocs,
+                 num_unfinished_relocs);
+
+            if (adjust_file && !dry_run)
+            {
+                /* Find out the new section sizes of the relocation sections,
+                   but do not move any relocations around, because adjust_elf
+                   needs to know about all relocations in order to adjust the
+                   file correctly.
+                */
+                match_relocation_sections_to_dynamic_ranges(source);
+
+                /* We haven't set up source->shdr_info[] yet, so we do it now.
+
+                   NOTE: setup_shdr_info() depends only on source->oldelf, not
+                   on source->elf!  source->elf is not even defined yet.  We
+                   initialize source->shdr_info[] based on the section
+                   information of the unmodified ELF file, and then make our
+                   modifications in the call to adjust_dynamic_segment() based
+                   on this information.  adjust_dynamic_segment() will
+                   rearrange the unhandled relocations in the beginning of
+                   their relocation sections, and adjust the size of those
+                   relocation sections.  In the case when a relocation section
+                   is completely handled, adjust_dynamic_segment() will mark it
+                   for removal by function adjust_elf.
+                 */
+
+                ASSERT(source->elf == source->oldelf);
+                ASSERT(source->shdr_info == NULL);
+                setup_shdr_info(source);
+                ASSERT(source->shdr_info != NULL);
+
+                INFO("\n\n\tADJUSTING DYNAMIC SEGMENT "
+                     "(CALCULATE CHANGES)\n\n");
+                bool drop_some_sections = adjust_dynamic_segment(source, true);
+
+                /* Reopen the elf file!  Note that we are not doing a dry run
+                   (the if statement above makes sure of that.)
+
+                   NOTE: We call init_elf() after we called
+                         adjust_dynamic_segment() in order to have
+                         adjust_dynamic_segment() refer to source->oldelf when
+                         it refers to source->elf.  Since
+                         adjust_dynamic_segment doesn't actually write to the
+                         ELF file, this is OK.  adjust_dynamic_segment()
+                         updates the sh_size fields of saved section headers
+                         and optionally marks sections for removal.
+
+                         Having adjust_dynamic_segment() refer to
+                         source->oldelf means that we'll have access to
+                         section-name strings so we can print them out in our
+                         logging and debug output.
+                */
+                source->elf = init_elf(source, false);
+
+                /* This is the same code as in init_source() after the call to
+                 * init_elf(). */
+                ASSERT(source->elf != source->oldelf);
+                ebl_closebackend(source->ebl);
+                source->ebl = ebl_openbackend (source->elf);
+                FAILIF_LIBELF(NULL == source->ebl, ebl_openbackend);
+#ifdef ARM_SPECIFIC_HACKS
+                FAILIF_LIBELF(0 != arm_init(source->elf,
+                                            source->elf_hdr.e_machine,
+                                            source->ebl, sizeof(Ebl)),
+                              arm_init);
+#endif/*ARM_SPECIFIC_HACKS*/
+
+                if (drop_some_sections)
+                    drop_sections(source);
+                else {
+                  INFO("All sections remain in [%s]--we are changing at "
+                       "most section sizes.\n", source->name);
+                    create_elf_sections(source, NULL);
+                    int cnt, idx;
+                    for (cnt = idx = 1; cnt < source->shnum; ++cnt) {
+                        Elf_Data *data = elf_getdata(
+                            source->shdr_info[cnt].newscn, // new section
+                            NULL);
+                        if (data->d_size !=
+                            source->shdr_info[cnt].shdr.sh_size) {
+                            INFO("Trimming new-section data from %d to %lld "
+                                 "bytes (as calculated by "
+                                 "adjust_dynamic_segment()).\n",
+                                 data->d_size,
+                                 source->shdr_info[cnt].shdr.sh_size);
+                            data->d_size = source->shdr_info[cnt].shdr.sh_size;
+                        }
+                    }
+                }
+
+                /* Shrink it! */
+                INFO("\n\n\tADJUSTING ELF\n\n");
+                adjust_elf(
+                    source->oldelf, source->name,
+                    source->elf, source->name,
+                    source->ebl,
+                    &source->old_ehdr_mem,
+                    NULL, 0, // no symbol filter
+                    source->shdr_info, // information on how to adjust the ELF
+                    source->shnum, // length of source->shdr_info[]
+                    source->phdr_info, // program-header info
+                    source->shnum, // irrelevant--we're not rebuilding shstrtab
+                    source->shnum, // number of sections in file
+                    source->shstrndx, // index of shstrtab (both in 
+                                      // shdr_info[] and as a section index)
+                    NULL, // irrelevant, since we are not rebuilding shstrtab
+                    drop_some_sections, // some sections are being dropped
+                    elf_ndxscn(source->dynamic.scn), // index of .dynamic
+                    elf_ndxscn(source->symtab.scn), // index of .dynsym
+                    1, // allow shady business
+                    &source->shstrtab_data,
+                    true,
+                    false); // do not rebuild shstrtab
+
+                INFO("\n\n\tREINITIALIZING STRUCTURES "
+                     "(TO CONTAIN ADJUSTMENTS)\n\n");
+                reinit_source(source);
+
+                INFO("\n\n\tPRELINKING (ACTUAL)\n\n");
+#ifdef DEBUG
+                int old_num_unfinished_relocs = num_unfinished_relocs;
+#endif
+                num_unfinished_relocs = 0;
+#ifdef DEBUG
+                int num_relocs_take_two =
+#endif
+                prelink(source, locals_only,
+                        false, /* not a dry run */
+                        lib_lookup_dirs, num_lib_lookup_dirs,
+                        default_libs, num_default_libs,
+                        &num_unfinished_relocs);
+
+                /* The numbers for the total number of relocations and the
+                   number of unhandled relocations between the first and second
+                   invokationof prelink() must be the same!  The first time we
+                   ran prelink() just to calculate the numbers so that we could
+                   calculate the adjustments to pass to adjust_elf, and the
+                   second time we actually carry out the prelinking; the
+                   numbers must stay the same!
+                */
+                ASSERT(num_relocs == num_relocs_take_two);
+                ASSERT(old_num_unfinished_relocs == num_unfinished_relocs);
+
+                INFO("[%s]: (actual prelink) handled %d, could not "
+                     "handle %d relocations.\n",
+                     source->name,
+                     num_relocs,
+                     num_unfinished_relocs);
+            } /* if (adjust_elf && !dry_run) */
+
+            *total_num_handled_relocs += num_relocs;
+            *total_num_unhandled_relocs += num_unfinished_relocs;
+
+            if(num_unfinished_relocs != 0 &&
+               source->elf_hdr.e_type != ET_EXEC &&
+               !locals_only)
+            {
+                /* One reason you could have unfinished relocations in an
+                   executable file is if this file used dlopen() and friends.
+                   We do not adjust relocation entries to those symbols,
+                   because libdl is a dummy only--the real functions are
+                   provided for by the dynamic linker itsef.
+
+                   NOTE FIXME HACK:  This is specific to the Android dynamic
+                   linker, and may not be true in other cases.
+                */
+                PRINT("WARNING: Expecting to have unhandled relocations only "
+                      "for executables (%s is not an executable)!\n",
+                      source->name);
+            }
+
+            match_relocation_sections_to_dynamic_ranges(source);
+
+            /* Now, for each relocation section, check to see if its address
+               matches one of the DT_DYNAMIC relocation pointers.  If so, then
+               if the section has no unhandled relocations, simply set the
+               associated DT_DYNAMIC entry's size to zero.  If the section does
+               have unhandled entries, then lump them all together at the front
+               of the respective section and update the size of the respective
+               DT_DYNAMIC entry to the new size of the section.  A better
+               approach would be do delete a relocation section if it has been
+               fully relocated and to remove its entry from the DT_DYNAMIC
+               array, and for relocation entries that still have some
+               relocations in them, we should shrink the section if that won't
+               violate relative offsets.  This is more work, however, and for
+               the speed improvement we expect from a prelinker, just patching
+               up DT_DYNAMIC will suffice.
+
+               Note: adjust_dynamic_segment() will modify source->shdr_info[]
+                     to denote any change in a relocation section's size.  This
+                     will be picked up by adjust_elf, which will rearrange the
+                     file to eliminate the gap created by the decrease in size
+                     of the relocation section.  We do not need to do this, but
+                     the relocation section could be large, and reduced
+                     drastically by the prelinking process, so it pays to
+                     adjust the file.
+            */
+
+            INFO("\n\n\tADJUSTING DYNAMIC SEGMENT (ACTUAL)\n\n");
+            adjust_dynamic_segment(source, false);
+        }
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+        else INFO("[%s] is already prelinked at 0x%08lx.\n",
+                  filename,
+                  source->prelink_base);
+#endif
+    } else INFO("[%s] has been processed already.\n", filename);
+
+    return source;
+}
+
+void apriori(char **execs, int num_execs,
+             char *output,
+             void (*report_library_size_in_memory)(
+                 const char *name, off_t fsize),
+             int (*get_next_link_address)(const char *name),
+             int locals_only,
+             int dry_run,
+             char **lib_lookup_dirs, int num_lib_lookup_dirs,
+             char **default_libs, int num_default_libs,
+                        char *mapfile)
+{
+    source_t *source; /* for general usage */
+    int input_idx;
+
+    ASSERT(report_library_size_in_memory != NULL);
+    ASSERT(get_next_link_address != NULL);
+
+    /* Process and prelink each executable and object file.  Function
+       process_file() is called for each executable in the loop below.
+       It calls itself recursively for each library.   We prelink each library
+       after prelinking its dependencies. */
+    int total_num_handled_relocs = 0, total_num_unhandled_relocs = 0;
+    for (input_idx = 0; input_idx < num_execs; input_idx++) {
+        INFO("executable: [%s]\n", execs[input_idx]);
+        /* Here process_file() is actually processing the top-level
+           executable files. */
+        process_file(execs[input_idx], output, num_execs == 1,
+                     report_library_size_in_memory,
+                     get_next_link_address, /* executables get a link address
+                                               of zero, regardless of this 
+                                               value */
+                     locals_only,
+                     lib_lookup_dirs, num_lib_lookup_dirs,
+                     default_libs, num_default_libs,
+                     dry_run,
+                     &total_num_handled_relocs,
+                     &total_num_unhandled_relocs);
+        /* if source is NULL, then the respective executable is static */
+        /* Mark the source as an executable */
+    } /* for each input executable... */
+
+    PRINT("Handled %d relocations.\n", total_num_handled_relocs);
+    PRINT("Could not handle %d relocations.\n", total_num_unhandled_relocs);
+
+    /* We are done!  Since the end result of our calculations is a set of
+       symbols for each library that other libraries or executables link
+       against, we iterate over the set of libraries one last time, and for
+       each symbol that is marked as satisfying some dependence, we emit
+       a line with the symbol's name to a text file derived from the library's
+       name by appending the suffix .syms to it. */
+
+    if (mapfile != NULL) {
+        const char *mapfile_name = mapfile;
+               FILE *fp;
+        if (*mapfile == '+') {
+            mapfile_name = mapfile + 1;
+            INFO("Opening map file %s for append/write.\n",
+                 mapfile_name);
+            fp = fopen(mapfile_name, "a");
+        }
+        else fp = fopen(mapfile_name, "w");
+
+               FAILIF(fp == NULL, "Cannot open file [%s]: %s (%d)!\n",
+                          mapfile_name,
+                          strerror(errno),
+                          errno);
+        source = sources;
+        while (source) {
+            /* If it's a library, print the results. */
+            if (source->elf_hdr.e_type == ET_DYN) {
+                /* Add to the memory map file. */
+                               fprintf(fp, "%s 0x%08lx %lld\n",
+                                               basename(source->name),
+                                               source->base,
+                                               source->elf_file_info.st_size);
+            }
+            source = source->next;
+        }
+               fclose(fp);
+    }
+
+    /* Free the resources--you can't do it in the loop above because function
+       print_symbol_references() accesses nodes other than the one being
+       iterated over.
+     */
+    source = sources;
+    while (source) {
+        source_t *old = source;
+        source = source->next;
+        /* Destroy the evidence. */
+        destroy_source(old);
+    }
+}
diff --git a/build/tools/apriori/apriori.h b/build/tools/apriori/apriori.h
new file mode 100644 (file)
index 0000000..5e396fd
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef LSD_H
+#define LSD_H
+
+void apriori(char **execs, int num_execs,
+             char *output,
+             void (*set_next_link_address)(const char *name, off_t fsize),
+             int (*get_next_link_address)(const char *name),
+             int locals_only,
+             int dry_run,
+             char **lib_lookup_dirs, int num_lib_lookup_dirs,
+             char **default_libs, int num_default_libs,
+                        char *mapfile);
+
+#endif
diff --git a/build/tools/apriori/cmdline.c b/build/tools/apriori/cmdline.c
new file mode 100644 (file)
index 0000000..95f112a
--- /dev/null
@@ -0,0 +1,186 @@
+#include <debug.h>
+#include <cmdline.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <ctype.h>
+
+extern char *optarg;
+extern int optind, opterr, optopt;
+
+static struct option long_options[] = {
+    {"start-address", required_argument, 0, 's'},
+    {"inc-address",   required_argument, 0, 'i'},
+    {"locals-only",   no_argument,       0, 'l'},
+    {"quiet",         no_argument,       0, 'Q'},
+    {"noupdate",      no_argument,       0, 'n'},
+    {"lookup",        required_argument, 0, 'L'},
+    {"default",       required_argument, 0, 'D'},
+    {"verbose",       no_argument,       0, 'V'},
+    {"help",          no_argument,       0, 'h'},
+       {"mapfile",       required_argument, 0, 'M'},
+       {"output",        required_argument, 0, 'o'},
+    {"prelinkmap",    required_argument, 0, 'p'},
+    {0, 0, 0, 0},
+};
+
+/* This array must parallel long_options[] */
+static const char *descriptions[] = {
+    "start address to prelink libraries to",
+    "address increment for each library",
+    "prelink local relocations only",
+    "suppress informational and non-fatal error messages",
+    "do a dry run--calculate the prelink info but do not update any files",
+    "provide a directory for library lookup",
+    "provide a default library or executable for symbol lookup",
+    "print verbose output",
+    "print help screen",
+       "print a list of prelink addresses to file (prefix filename with + to append instead of overwrite)",
+    "specify an output directory (if multiple inputs) or file (is single input)",
+    "specify a file with prelink addresses instead of a --start-address/--inc-address combination",
+};
+
+void print_help(const char *name) {
+    fprintf(stdout,
+            "invokation:\n"
+            "\t%s file1 [file2 file3 ...] -Ldir1 [-Ldir2 ...] -saddr -iinc [-Vqn] [-M<logfile>]\n"
+            "\t%s -l file [-Vqn] [-M<logfile>]\n"
+            "\t%s -h\n\n", name, name, name);
+    fprintf(stdout, "options:\n");
+    struct option *opt = long_options;
+    const char **desc = descriptions;
+    while (opt->name) {
+        fprintf(stdout, "\t-%c/--%s%s: %s\n",
+                opt->val,
+                opt->name,
+                (opt->has_arg ? " (argument)" : ""),
+                *desc);
+        opt++;
+        desc++;
+    }
+}
+
+int get_options(int argc, char **argv,
+                int *start_addr,
+                int *inc_addr,
+                int *locals_only,
+                int *quiet,
+                int *dry_run,
+                char ***dirs,
+                int *num_dirs,
+                char ***defaults,
+                int *num_defaults,
+                int *verbose,
+                               char **mapfile,
+                char **output,
+                char **prelinkmap) {
+    int c;
+
+    ASSERT(dry_run); *dry_run = 0;
+    ASSERT(quiet); *quiet = 0;
+    ASSERT(verbose); *verbose = 0;
+    ASSERT(dirs); *dirs = NULL;
+    ASSERT(num_dirs); *num_dirs = 0;
+    ASSERT(defaults); *defaults = NULL;
+    ASSERT(num_defaults); *num_defaults = 0;
+    ASSERT(start_addr); *start_addr = -1;
+    ASSERT(inc_addr); *inc_addr =   -1;
+    ASSERT(locals_only); *locals_only = 0;
+       ASSERT(mapfile); *mapfile = NULL;
+       ASSERT(output); *output = NULL;
+    ASSERT(prelinkmap); *prelinkmap = NULL;
+    int dirs_size = 0;
+    int defaults_size = 0;
+
+    while (1) {
+        /* getopt_long stores the option index here. */
+        int option_index = 0;
+
+        c = getopt_long (argc, argv,
+                         "VhnQlL:D:s:i:M:o:p:",
+                         long_options,
+                         &option_index);
+        /* Detect the end of the options. */
+        if (c == -1) break;
+
+        if (isgraph(c)) {
+            INFO ("option -%c with value `%s'\n", c, (optarg ?: "(null)"));
+        }
+
+#define SET_STRING_OPTION(name) do {                                   \
+    ASSERT(optarg);                                                    \
+    (*name) = strdup(optarg);                                          \
+} while(0)
+
+#define SET_REPEATED_STRING_OPTION(arr, num, size) do {                \
+       if (*num == size) {                                                \
+               size += 10;                                                    \
+               *arr = (char **)REALLOC(*arr, size * sizeof(char *));          \
+       }                                                                  \
+       SET_STRING_OPTION(((*arr) + *num));                                \
+       (*num)++;                                                          \
+} while(0)
+
+#define SET_INT_OPTION(val) do {                                       \
+    ASSERT(optarg);                                                    \
+       if (strlen(optarg) >= 2 && optarg[0] == '0' && optarg[1] == 'x') { \
+                       FAILIF(1 != sscanf(optarg+2, "%x", val),                   \
+                                  "Expecting a hexadecimal argument!\n");             \
+       } else {                                                           \
+               FAILIF(1 != sscanf(optarg, "%d", val),                         \
+                          "Expecting a decimal argument!\n");                     \
+       }                                                                  \
+} while(0)
+
+        switch (c) {
+        case 0:
+            /* If this option set a flag, do nothing else now. */
+            if (long_options[option_index].flag != 0)
+                break;
+            INFO ("option %s", long_options[option_index].name);
+            if (optarg)
+                INFO (" with arg %s", optarg);
+            INFO ("\n");
+            break;
+        case 'Q': *quiet = 1; break;
+               case 'n': *dry_run = 1; break;
+               case 'M':
+                       SET_STRING_OPTION(mapfile);
+                       break;
+               case 'o':
+                       SET_STRING_OPTION(output);
+                       break;
+        case 'p':
+            SET_STRING_OPTION(prelinkmap);
+            break;
+        case 's':
+            SET_INT_OPTION(start_addr);
+            break;
+        case 'i':
+            SET_INT_OPTION(inc_addr);
+            break;
+        case 'L':
+            SET_REPEATED_STRING_OPTION(dirs, num_dirs, dirs_size);
+            break;
+        case 'D':
+            SET_REPEATED_STRING_OPTION(defaults, num_defaults, defaults_size);
+            break;
+        case 'l': *locals_only = 1; break;
+        case 'h': print_help(argv[0]); exit(1); break;
+        case 'V': *verbose = 1; break;
+        case '?':
+            /* getopt_long already printed an error message. */
+            break;
+
+#undef SET_STRING_OPTION
+#undef SET_REPEATED_STRING_OPTION
+#undef SET_INT_OPTION
+
+        default:
+            FAILIF(1, "Unknown option");
+        }
+    }
+
+    return optind;
+}
diff --git a/build/tools/apriori/cmdline.h b/build/tools/apriori/cmdline.h
new file mode 100644 (file)
index 0000000..8f7f394
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef CMDLINE_H
+#define CMDLINE_H
+
+void print_help(const char *executable_name);
+
+int get_options(int argc, char **argv,
+                int *start_addr,
+                int *addr_increment,
+                int *locals_only,
+                int *quiet,
+                int *dry_run,
+                char ***dirs,
+                int *num_dirs,
+                char ***defaults,
+                int *num_defaults,
+                int *verbose,
+                               char **mapfile,
+                char **output,
+                char **prelinkmap);
+
+#endif/*CMDLINE_H*/
diff --git a/build/tools/apriori/common.h b/build/tools/apriori/common.h
new file mode 100644 (file)
index 0000000..f5d9d2e
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <libelf.h>
+#include <elf.h>
+
+#define unlikely(expr) __builtin_expect (expr, 0)
+#define likely(expr)   __builtin_expect (expr, 1)
+
+#define MIN(a,b) ((a)<(b)?(a):(b)) /* no side effects in arguments allowed! */
+
+static inline int is_host_little(void)
+{
+    short val = 0x10;
+    return ((char *)&val)[0] != 0;
+}
+
+static inline long switch_endianness(long val)
+{
+       long newval;
+       ((char *)&newval)[3] = ((char *)&val)[0];
+       ((char *)&newval)[2] = ((char *)&val)[1];
+       ((char *)&newval)[1] = ((char *)&val)[2];
+       ((char *)&newval)[0] = ((char *)&val)[3];
+       return newval;
+}
+
+#endif/*COMMON_H*/
diff --git a/build/tools/apriori/debug.c b/build/tools/apriori/debug.c
new file mode 100644 (file)
index 0000000..263e09f
--- /dev/null
@@ -0,0 +1,38 @@
+#include <debug.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#define NUM_COLS  (32)
+
+int dump_hex_buffer(FILE *s, void *b, size_t len, size_t elsize) {
+    int num_nonprintable = 0;
+    int i, last;
+    char *pchr = (char *)b;
+    fputc('\n', s);
+    fprintf(s, "%p: ", b);
+    for (i = last = 0; i < len; i++) {
+        if (!elsize) {
+            if (i && !(i % 4)) fprintf(s, " ");
+            if (i && !(i % 8)) fprintf(s, " ");
+        } else {
+            if (i && !(i % elsize)) fprintf(s, " ");
+        }
+
+        if (i && !(i % NUM_COLS)) {
+            while (last < i) {
+                if (isprint(pchr[last]))
+                    fputc(pchr[last], s);
+                else {
+                    fputc('.', s); 
+                    num_nonprintable++;
+                }
+                last++;
+            }
+            fprintf(s, " (%d)\n%p: ", i, b);
+        }
+        fprintf(s, "%02x", (unsigned char)pchr[i]);
+    }
+    if (i && (i % NUM_COLS)) fputs("\n", s);
+    return num_nonprintable;
+}
+
diff --git a/build/tools/apriori/debug.h b/build/tools/apriori/debug.h
new file mode 100644 (file)
index 0000000..3996898
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <common.h>
+
+#ifdef DEBUG
+
+    #define FAILIF(cond, msg...) do {                        \
+       if (unlikely(cond)) {                                \
+        fprintf(stderr, "%s(%d): ", __FILE__, __LINE__); \
+               fprintf(stderr, ##msg);                          \
+               exit(1);                                         \
+       }                                                    \
+} while(0)
+
+/* Debug enabled */
+    #define ASSERT(x) do {                                \
+       if (unlikely(!(x))) {                             \
+               fprintf(stderr,                               \
+                               "ASSERTION FAILURE %s:%d: [%s]\n",    \
+                               __FILE__, __LINE__, #x);              \
+               exit(1);                                      \
+       }                                                 \
+} while(0)
+
+#else
+
+    #define FAILIF(cond, msg...) do { \
+       if (unlikely(cond)) {         \
+               fprintf(stderr, ##msg);   \
+               exit(1);                  \
+       }                             \
+} while(0)
+
+/* No debug */
+    #define ASSERT(x)   do { } while(0)
+
+#endif/* DEBUG */
+
+#define FAILIF_LIBELF(cond, function) \
+    FAILIF(cond, "%s(): %s\n", #function, elf_errmsg(elf_errno()));
+
+static inline void *MALLOC(unsigned int size) {
+    void *m = malloc(size);
+    FAILIF(NULL == m, "malloc(%d) failed!\n", size);
+    return m;
+}
+
+static inline void *CALLOC(unsigned int num_entries, unsigned int entry_size) {
+    void *m = calloc(num_entries, entry_size);
+    FAILIF(NULL == m, "calloc(%d, %d) failed!\n", num_entries, entry_size);
+    return m;
+}
+
+static inline void *REALLOC(void *ptr, unsigned int size) {
+    void *m = realloc(ptr, size);
+    FAILIF(NULL == m, "realloc(%p, %d) failed!\n", ptr, size);
+    return m;
+}
+
+static inline void FREE(void *ptr) {
+    free(ptr);
+}
+
+static inline void FREEIF(void *ptr) {
+    if (ptr) FREE(ptr);
+}
+
+#define PRINT(x...)  do {                             \
+    extern int quiet_flag;                            \
+    if(likely(!quiet_flag))                           \
+        fprintf(stdout, ##x);                         \
+} while(0)
+
+#define ERROR PRINT
+
+#define INFO(x...)  do {                              \
+    extern int verbose_flag;                          \
+    if(unlikely(verbose_flag))                        \
+        fprintf(stdout, ##x);                         \
+} while(0)
+
+/* Prints a hex and ASCII dump of the selected buffer to the selected stream. */
+int dump_hex_buffer(FILE *s, void *b, size_t l, size_t elsize);
+
+#endif/*DEBUG_H*/
diff --git a/build/tools/apriori/hash.c b/build/tools/apriori/hash.c
new file mode 100644 (file)
index 0000000..9f1a614
--- /dev/null
@@ -0,0 +1,27 @@
+#include <common.h>
+#include <debug.h>
+#include <libelf.h>
+#include <hash.h>
+#include <string.h>
+
+int hash_lookup(Elf *elf, 
+                Elf_Data *hash,
+                Elf_Data *symtab,
+                Elf_Data *symstr,
+                const char *symname) {
+    Elf32_Word *hash_data = (Elf32_Word *)hash->d_buf;
+    Elf32_Word index;
+    Elf32_Word nbuckets = *hash_data++;
+    Elf32_Word *buckets = ++hash_data;
+    Elf32_Word *chains  = hash_data + nbuckets;
+
+    index = buckets[elf_hash(symname) % nbuckets];
+    while (index != STN_UNDEF &&
+           strcmp((char *)symstr->d_buf + 
+                  ((Elf32_Sym *)symtab->d_buf)[index].st_name,
+                  symname)) {
+        index = chains[index];
+    }
+
+    return index;
+}
diff --git a/build/tools/apriori/hash.h b/build/tools/apriori/hash.h
new file mode 100644 (file)
index 0000000..af29b9e
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef HASH_H
+#define HASH_H
+
+#include <common.h>
+#include <libelf.h>
+#include <gelf.h>
+
+int hash_lookup(Elf *elf, 
+                Elf_Data *hash,
+                Elf_Data *symtab,
+                Elf_Data *symstr,
+                const char *symname);
+
+#endif/*HASH_H*/
diff --git a/build/tools/apriori/main.c b/build/tools/apriori/main.c
new file mode 100644 (file)
index 0000000..552392a
--- /dev/null
@@ -0,0 +1,229 @@
+/* TODO:
+   1. check the ARM EABI version--this works for versions 1 and 2.
+   2. use a more-intelligent approach to finding the symbol table,
+      symbol-string table, and the .dynamic section.
+   3. fix the determination of the host and ELF-file endianness
+   4. write the help screen
+*/
+
+#include <stdio.h>
+#include <common.h>
+#include <debug.h>
+#include <libelf.h>
+#include <elf.h>
+#include <gelf.h>
+#include <cmdline.h>
+#include <string.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <apriori.h>
+#include <prelinkmap.h>
+
+/* Flag set by --verbose.  This variable is global as it is accessed by the
+   macro INFO() in multiple compilation unites. */
+int verbose_flag = 0;
+/* Flag set by --quiet.  This variable is global as it is accessed by the
+   macro PRINT() in multiple compilation unites. */
+int quiet_flag = 0;
+static void print_dynamic_symbols(Elf *elf, const char *symtab_name);
+
+static unsigned s_next_link_addr;
+static off_t s_addr_increment;
+
+static void report_library_size_in_memory(const char *name, off_t fsize)
+{
+    ASSERT(s_next_link_addr != -1UL);
+       INFO("Setting next link address (current is at 0x%08x):\n",
+         s_next_link_addr);
+       if (s_addr_increment) {
+               FAILIF(s_addr_increment < fsize,
+                          "Command-line-specified address increment of 0x%08llx (%lld) "
+               "less than file [%s]'s size of %lld bytes!\n",
+                          s_addr_increment, s_addr_increment, name, fsize);
+               FAILIF(s_next_link_addr % 4096,
+                          "User-provided address increment 0x%08lx "
+               "is not page-aligned!\n",
+                          s_addr_increment);
+               INFO("\tignoring file size, adjusting by address increment.\n");
+               s_next_link_addr += s_addr_increment;
+       }
+       else {
+               INFO("\tuser address increment is zero, adjusting by file size.\n");
+               s_next_link_addr += fsize;
+               s_next_link_addr &= ~(4096 - 1);
+       }
+       INFO("\t[%s] file size 0x%08lx\n",
+                name,
+                fsize);
+       INFO("\tnext prelink address: 0x%08x\n", s_next_link_addr);
+       ASSERT(!(s_next_link_addr % 4096)); /* New address must be page-aligned */
+}
+
+static unsigned get_next_link_address(const char *name) {
+    return s_next_link_addr;
+}
+
+int main(int argc, char **argv) {
+    /* Do not issue INFO() statements before you call get_options() to set
+       the verbose flag as necessary.
+    */
+
+    char **lookup_dirs, **default_libs;
+       char *mapfile, *output, *prelinkmap;
+    int start_addr, inc_addr, locals_only, num_lookup_dirs, 
+        num_default_libs, dry_run;
+    int first = get_options(argc, argv,
+                            &start_addr, &inc_addr, &locals_only,
+                            &quiet_flag,
+                            &dry_run,
+                            &lookup_dirs, &num_lookup_dirs,
+                            &default_libs, &num_default_libs,
+                            &verbose_flag,
+                                                       &mapfile,
+                            &output,
+                            &prelinkmap);
+
+    /* Perform some command-line-parameter checks. */
+    int cmdline_err = 0;
+    if (first == argc) {
+        ERROR("You must specify at least one input ELF file!\n");
+        cmdline_err++;
+    }
+    /* We complain when the user does not specify a start address for
+       prelinking when the user does not pass the locals_only switch.  The
+       reason is that we will have a collection of executables, which we always
+       prelink to zero, and shared libraries, which we prelink at the specified
+       prelink address.  When the user passes the locals_only switch, we do not
+       fail if the user does not specify start_addr, because the file to
+       prelink may be an executable, and not a shared library.  At this moment,
+       we do not know what the case is.  We find that out when we call function
+       init_source().
+    */
+    if (!locals_only && start_addr == -1) {
+        ERROR("You must specify --start-addr!\n");
+        cmdline_err++;
+    }
+    if (start_addr == -1 && inc_addr != -1) {
+        ERROR("You must provide a start address if you provide an "
+              "address increment!\n");
+        cmdline_err++;
+    }
+    if (prelinkmap != NULL && start_addr != -1) {
+        ERROR("You may not provide a prelink-map file (-p) and use -s/-i "
+              "at the same time!\n");
+        cmdline_err++;
+    }
+    if (inc_addr == 0) {
+        ERROR("You may not specify a link-address increment of zero!\n");
+        cmdline_err++;
+    }
+    if (locals_only) {
+        if (argc - first == 1) {
+            if (inc_addr != -1) {
+                ERROR("You are prelinking a single file; there is no point in "
+                      "specifying a prelink-address increment!\n");
+                /* This is nonfatal error, but paranoia is healthy. */
+                cmdline_err++;
+            }
+        }
+        if (lookup_dirs != NULL || default_libs != NULL) {
+            ERROR("You are prelinking local relocations only; there is "
+                  "no point in specifying lookup directories!\n");
+            /* This is nonfatal error, but paranoia is healthy. */
+            cmdline_err++;
+        }
+    }
+
+    /* If there is an output option, then that must specify a file, if there is
+       a single input file, or a directory, if there are multiple input
+       files. */
+    if (output != NULL) {
+        struct stat output_st;
+        FAILIF(stat(output, &output_st) < 0 && errno != ENOENT,
+               "stat(%s): %s (%d)\n",
+               output,
+               strerror(errno),
+               errno);
+
+        if (argc - first == 1) {
+            FAILIF(!errno && !S_ISREG(output_st.st_mode),
+                   "you have a single input file: -o must specify a "
+                   "file name!\n");
+        }
+        else {
+            FAILIF(errno == ENOENT,
+                   "you have multiple input files: -o must specify a "
+                   "directory name, but %s does not exist!\n",
+                   output);
+            FAILIF(!S_ISDIR(output_st.st_mode),
+                   "you have multiple input files: -o must specify a "
+                   "directory name, but %s is not a directory!\n",
+                   output);
+        }
+    }
+
+    if (cmdline_err) {
+        print_help(argv[0]);
+        FAILIF(1, "There are command-line-option errors.\n");
+    }
+
+    /* Check to see whether the ELF library is current. */
+    FAILIF (elf_version(EV_CURRENT) == EV_NONE, "libelf is out of date!\n");
+
+       if (inc_addr < 0) {
+        if (!locals_only)
+            PRINT("User has not provided an increment address, "
+                  "will use library size to calculate successive "
+                  "prelink addresses.\n");
+        inc_addr = 0;
+       }
+
+    void (*func_report_library_size_in_memory)(const char *name, off_t fsize);
+    unsigned (*func_get_next_link_address)(const char *name);
+
+    if (prelinkmap != NULL) {
+        INFO("Reading prelink addresses from prelink-map file [%s].\n",
+             prelinkmap);
+        pm_init(prelinkmap);
+        func_report_library_size_in_memory = pm_report_library_size_in_memory;
+        func_get_next_link_address = pm_get_next_link_address;
+    }
+    else {
+        INFO("Start address: 0x%x\n", start_addr);
+        INFO("Increment address: 0x%x\n", inc_addr);
+        s_next_link_addr = start_addr;
+        s_addr_increment = inc_addr;
+        func_report_library_size_in_memory = report_library_size_in_memory;
+        func_get_next_link_address = get_next_link_address;
+    }
+
+    /* Prelink... */
+    apriori(&argv[first], argc - first, output,
+            func_report_library_size_in_memory, func_get_next_link_address,
+            locals_only,
+            dry_run,
+            lookup_dirs, num_lookup_dirs,
+            default_libs, num_default_libs,
+                       mapfile);
+
+       FREEIF(mapfile);
+    FREEIF(output);
+       if (lookup_dirs) {
+               ASSERT(num_lookup_dirs);
+               while (num_lookup_dirs--)
+                       FREE(lookup_dirs[num_lookup_dirs]);
+               FREE(lookup_dirs);
+       }
+       if (default_libs) {
+               ASSERT(num_default_libs);
+               while (num_default_libs--)
+                       FREE(default_libs[num_default_libs]);
+               FREE(default_libs);
+       }
+
+    return 0;
+}
diff --git a/build/tools/apriori/prelink_info.c b/build/tools/apriori/prelink_info.c
new file mode 100644 (file)
index 0000000..da7ca05
--- /dev/null
@@ -0,0 +1,106 @@
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <prelink_info.h>
+#include <debug.h>
+#include <common.h>
+
+typedef struct {
+       int32_t mmap_addr;
+       char tag[4]; /* 'P', 'R', 'E', ' ' */
+} prelink_info_t __attribute__((packed));
+
+static inline void set_prelink(long *prelink_addr, 
+                                                          int elf_little,
+                                                          prelink_info_t *info)
+{
+    FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %d!\n", sizeof(prelink_info_t));
+       if (prelink_addr) {
+               if (!(elf_little ^ is_host_little())) {
+                       /* Same endianness */
+                       *prelink_addr = info->mmap_addr;
+               }
+               else {
+                       /* Different endianness */
+                       *prelink_addr = switch_endianness(info->mmap_addr);
+               }
+       }
+}
+
+int check_prelinked(const char *fname, int elf_little, long *prelink_addr)
+{
+    FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %d!\n", sizeof(prelink_info_t));
+       int fd = open(fname, O_RDONLY);
+       FAILIF(fd < 0, "open(%s, O_RDONLY): %s (%d)!\n",
+                  fname, strerror(errno), errno);
+       off_t end = lseek(fd, 0, SEEK_END);
+
+    int nr = sizeof(prelink_info_t);
+
+    off_t sz = lseek(fd, -nr, SEEK_CUR);
+       ASSERT((long)(end - sz) == (long)nr);
+       FAILIF(sz == (off_t)-1, 
+                  "lseek(%d, 0, SEEK_END): %s (%d)!\n", 
+                  fd, strerror(errno), errno);
+
+       prelink_info_t info;
+       int num_read = read(fd, &info, nr);
+       FAILIF(num_read < 0, 
+                  "read(%d, &info, sizeof(prelink_info_t)): %s (%d)!\n",
+                  fd, strerror(errno), errno);
+       FAILIF(num_read != sizeof(info),
+                  "read(%d, &info, sizeof(prelink_info_t)): did not read %d bytes as "
+                  "expected (read %d)!\n",
+                  fd, sizeof(info), num_read);
+
+       int prelinked = 0;
+       if (!strncmp(info.tag, "PRE ", 4)) {
+               set_prelink(prelink_addr, elf_little, &info);
+               prelinked = 1;
+       }
+       FAILIF(close(fd) < 0, "close(%d): %s (%d)!\n", fd, strerror(errno), errno);
+       return prelinked;
+}
+
+void setup_prelink_info(const char *fname, int elf_little, long base)
+{
+    FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %d!\n", sizeof(prelink_info_t));
+    int fd = open(fname, O_WRONLY);
+    FAILIF(fd < 0, 
+           "open(%s, O_WRONLY): %s (%d)\n" ,
+           fname, strerror(errno), errno);
+    prelink_info_t info;
+    off_t sz = lseek(fd, 0, SEEK_END);
+    FAILIF(sz == (off_t)-1, 
+           "lseek(%d, 0, SEEK_END): %s (%d)!\n", 
+           fd, strerror(errno), errno);
+
+    if (!(elf_little ^ is_host_little())) {
+        /* Same endianness */
+        INFO("Host and ELF file [%s] have same endianness.\n", fname);
+        info.mmap_addr = base;
+    }
+    else {
+        /* Different endianness */
+        INFO("Host and ELF file [%s] have different endianness.\n", fname);
+               info.mmap_addr = switch_endianness(base);
+    }
+    strncpy(info.tag, "PRE ", 4);
+
+    int num_written = write(fd, &info, sizeof(info));
+    FAILIF(num_written < 0, 
+           "write(%d, &info, sizeof(info)): %s (%d)\n",
+           fd, strerror(errno), errno);
+    FAILIF(sizeof(info) != num_written, 
+           "Could not write %d bytes (wrote only %d bytes) as expected!\n",
+           sizeof(info), num_written);
+    FAILIF(close(fd) < 0, "close(%d): %s (%d)!\n", fd, strerror(errno), errno);
+}
+
+#endif /*SUPPORT_ANDROID_PRELINK_TAGS*/
diff --git a/build/tools/apriori/prelink_info.h b/build/tools/apriori/prelink_info.h
new file mode 100644 (file)
index 0000000..e2787cb
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef PRELINK_INFO_H
+#define PRELINK_INFO_H
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+
+int check_prelinked(const char *fname, int elf_little, long *prelink_addr);
+void setup_prelink_info(const char *fname, int elf_little, long base);
+
+#endif
+#endif/*PRELINK_INFO_H*/
diff --git a/build/tools/apriori/prelinkmap.c b/build/tools/apriori/prelinkmap.c
new file mode 100644 (file)
index 0000000..9fb00e4
--- /dev/null
@@ -0,0 +1,170 @@
+#include <prelinkmap.h>
+#include <debug.h>
+#include <errno.h>
+#include <string.h>
+#include <libgen.h>
+#include <ctype.h>
+
+typedef struct mapentry mapentry;
+
+#define MAX_ALIASES 10
+
+struct mapentry
+{
+    mapentry *next;
+    unsigned base;
+    char *names[MAX_ALIASES];
+    int num_names;
+};
+
+static mapentry *maplist = 0;
+
+/* These values limit the address range within which we prelinked libraries
+   reside.  The limit is not set in stone, but should be observed in the 
+   prelink map, or the prelink step will fail.
+*/
+
+#define PRELINK_MIN 0x90000000
+#define PRELINK_MAX 0xBFFFFFFF
+
+void pm_init(const char *file)
+{
+    unsigned line = 0;
+    char buf[256];
+    char *x;
+    FILE *fp;
+    mapentry *me;
+    unsigned last = -1UL;
+    
+    fp = fopen(file, "r");
+    FAILIF(fp == NULL, "Error opening file %s: %s (%d)\n", 
+           file, strerror(errno), errno);
+
+    while(fgets(buf, 256, fp)){
+        x = buf;
+        line++;
+        
+        /* eat leading whitespace */
+        while(isspace(*x)) x++;
+
+        /* comment or blank line? skip! */
+        if(*x == '#') continue;
+        if(*x == 0) continue;
+
+        /* skip name */
+        while(*x && !isspace(*x)) x++;
+
+        if(*x) {
+            *x++ = 0;
+            /* skip space before address */
+            while(*x && isspace(*x)) x++;
+        }
+
+        /* no address? complain. */
+        if(*x == 0) {
+            fprintf(stderr,"warning: %s:%d no base address specified\n",
+                    file, line);
+            continue;
+        }
+        
+        if (isalpha(*x)) {
+            /* Assume that this is an alias, and look through the list of
+               already-installed libraries.
+            */
+            me = maplist;
+            while(me) {
+                /* The strlen() call ignores the newline at the end of x */
+                if (!strncmp(me->names[0], x, strlen(me->names[0]))) {
+                    PRINT("Aliasing library %s to %s at %08x\n",
+                          buf, x, me->base);
+                    break;
+                }
+                me = me->next;
+            }
+            FAILIF(!me, "Nonexistent alias %s -> %s\n", buf, x);
+        }
+        else {
+            unsigned n = strtoul(x, 0, 16);
+            /* Note that this is not the only bounds check.  If a library's
+               size exceeds its slot as defined in the prelink map, the
+               prelinker will exit with an error.  See
+               pm_report_library_size_in_memory().
+            */
+            FAILIF((n < PRELINK_MIN) || (n > PRELINK_MAX),
+                   "%s:%d base 0x%08x out of range.\n",
+                   file, line, n);
+
+            me = malloc(sizeof(mapentry));
+            FAILIF(me == NULL, "Out of memory parsing %s\n", file);
+
+            FAILIF(last <= n, "The prelink map is not in descending order "
+                   "at entry %s (%08x)!\n", buf, n);
+            last = n;
+
+            me->base = n;
+            me->next = maplist;
+            me->num_names = 0;
+            maplist = me;
+        }
+
+        FAILIF(me->num_names >= MAX_ALIASES,
+               "Too many aliases for library %s, maximum is %d.\n",
+               me->names[0],
+               MAX_ALIASES);
+        me->names[me->num_names] = strdup(buf);
+        me->num_names++;
+    }
+
+    fclose(fp);
+}
+
+/* apriori() calls this function when it determine the size of a library 
+   in memory.  pm_report_library_size_in_memory() makes sure that the library
+   fits in the slot provided by the prelink map.
+*/
+void pm_report_library_size_in_memory(const char *name,
+                                      off_t fsize)
+{
+    char *x;
+    mapentry *me;
+    int n;
+    
+    x = strrchr(name,'/');
+    if(x) name = x+1;
+
+    for(me = maplist; me; me = me->next){
+        for (n = 0; n < me->num_names; n++) {
+            if(!strcmp(name, me->names[n])) {
+                off_t slot = me->next ? me->next->base : PRELINK_MAX;
+                slot -= me->base;
+                FAILIF(fsize > slot,
+                       "prelink map error: library %s@0x%08x is too big "
+                       "at %lld bytes, it runs %lld bytes into "
+                       "library %s@0x%08x!\n",
+                       me->names[0], me->base, fsize, fsize - slot,
+                       me->next->names[0], me->next->base);
+                return;
+            }
+        }
+    }
+    
+    FAILIF(1, "library '%s' not in prelink map\n", name);
+}
+
+unsigned pm_get_next_link_address(const char *lookup_name)
+{
+    char *x;
+    mapentry *me;
+    int n;
+    
+    x = strrchr(lookup_name,'/');
+    if(x) lookup_name = x+1;
+    
+    for(me = maplist; me; me = me->next)
+        for (n = 0; n < me->num_names; n++)
+            if(!strcmp(lookup_name, me->names[n]))
+                return me->base;
+
+    FAILIF(1, "library '%s' not in prelink map\n", lookup_name);
+    return 0;
+}
diff --git a/build/tools/apriori/prelinkmap.h b/build/tools/apriori/prelinkmap.h
new file mode 100644 (file)
index 0000000..17f7660
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef PRELINKMAP_H
+#define PRELINKMAP_H
+
+#include <sys/types.h>
+
+extern void pm_init(const char *file);
+extern void pm_report_library_size_in_memory(const char *name, off_t fsize);
+extern unsigned pm_get_next_link_address(const char *name);
+
+#endif/*PRELINKMAP_H*/
diff --git a/build/tools/apriori/rangesort.c b/build/tools/apriori/rangesort.c
new file mode 100644 (file)
index 0000000..b0295e8
--- /dev/null
@@ -0,0 +1,317 @@
+#include <common.h>
+#include <debug.h>
+#include <rangesort.h>
+
+#define PARALLEL_ARRAY_SIZE (5)
+
+struct range_list_t {
+    range_t *array;
+#ifdef DEBUG
+    int is_sorted;
+#endif
+    int array_length;
+    int num_ranges;
+};
+
+range_list_t* init_range_list(void) {
+    range_list_t *ranges = (range_list_t *)MALLOC(sizeof(range_list_t));
+
+    ranges->array = (range_t *)MALLOC(PARALLEL_ARRAY_SIZE*sizeof(range_t));
+    ranges->array_length = PARALLEL_ARRAY_SIZE;
+    ranges->num_ranges = 0;
+#ifdef DEBUG
+    ranges->is_sorted = 0;
+#endif
+    return ranges; 
+}
+
+void destroy_range_list(range_list_t *ranges) {
+    int idx;
+    for (idx = 0; idx < ranges->num_ranges; idx++) {
+        if (ranges->array[idx].user_dtor) {
+            ASSERT(ranges->array[idx].user);
+            ranges->array[idx].user_dtor(ranges->array[idx].user);
+        }
+    }
+    FREE(ranges->array);
+    FREE(ranges);
+}
+
+static inline int CONTAINS(range_t *container, range_t *contained) {
+    return container->start <= contained->start && contained->length && 
+    (container->start + container->length > 
+     contained->start + contained->length);
+}
+
+static inline int IN_RANGE(range_t *range, GElf_Off point) {
+    return 
+    range->start <= point && 
+    point < (range->start + range->length);
+}
+
+static inline int INTERSECT(range_t *left, range_t *right) {
+    return 
+    (IN_RANGE(left, right->start) && 
+     IN_RANGE(right, left->start + left->length)) ||
+    (IN_RANGE(right, left->start) && 
+     IN_RANGE(left, right->start + right->length));
+}
+
+static int range_cmp_for_search(const void *l, const void *r) {
+    range_t *left = (range_t *)l, *right = (range_t *)r;
+    if (INTERSECT(left, right) ||
+        CONTAINS(left, right) ||
+        CONTAINS(right, left)) {
+        return 0;
+    }
+    return left->start - right->start;
+}
+
+static inline void run_checks(const void *l, const void *r) {
+    range_t *left = (range_t *)l, *right = (range_t *)r;
+    if (CONTAINS(left, right)) {
+        if (left->err_fn)
+            left->err_fn(ERROR_CONTAINS, left, right);
+        FAILIF(1, "Range sorting error: [%lld, %lld) contains [%lld, %lld)!\n",
+               left->start, left->start + left->length,
+               right->start, right->start + right->length);
+    }
+    if (CONTAINS(right, left)) {
+        if (right->err_fn)
+            right->err_fn(ERROR_CONTAINS, left, right);
+        FAILIF(1, "Range sorting error: [%lld, %lld) contains [%lld, %lld)!\n",
+               right->start, right->start + right->length,
+               left->start, left->start + left->length);
+    }
+    if (INTERSECT(left, right)) {
+        if (left->err_fn)
+            left->err_fn(ERROR_OVERLAPS, left, right);
+        FAILIF(1, "Range sorting error: [%lld, %lld)and [%lld, %lld) intersect!\n",
+               left->start, left->start + left->length,
+               right->start, right->start + right->length);
+    }
+}
+
+static int range_cmp(const void *l, const void *r) {
+    run_checks(l, r);
+    range_t *left = (range_t *)l, *right = (range_t *)r;
+    return left->start - right->start;
+}
+
+void add_unique_range_nosort(
+                            range_list_t *ranges, 
+                            GElf_Off start, 
+                            GElf_Off length, 
+                            void *user,
+                            void (*err_fn)(range_error_t, range_t *, range_t *),
+                            void (*user_dtor)(void * )) 
+{
+    if (ranges->num_ranges == ranges->array_length) {
+        ranges->array_length += PARALLEL_ARRAY_SIZE;
+        ranges->array = REALLOC(ranges->array, 
+                                ranges->array_length*sizeof(range_t));
+    }
+    ranges->array[ranges->num_ranges].start  = start;
+    ranges->array[ranges->num_ranges].length = length;
+    ranges->array[ranges->num_ranges].user   = user;
+    ranges->array[ranges->num_ranges].err_fn = err_fn;
+    ranges->array[ranges->num_ranges].user_dtor = user_dtor;
+    ranges->num_ranges++;
+}
+
+range_list_t *sort_ranges(range_list_t *ranges) {
+    if (ranges->num_ranges > 1)
+        qsort(ranges->array, ranges->num_ranges, sizeof(range_t), range_cmp);
+    ranges->is_sorted = 1;
+    return ranges;
+}
+
+range_t *find_range(range_list_t *ranges, GElf_Off value) {
+#if 1
+    int i;
+    for (i = 0; i < ranges->num_ranges; i++) {
+        if (ranges->array[i].start <= value && 
+            value < ranges->array[i].start + ranges->array[i].length)
+            return ranges->array + i;
+    }
+    return NULL;
+#else
+    ASSERT(ranges->is_sorted); /* The range list must be sorted */
+    range_t lookup;
+    lookup.start = value;
+    lookup.length = 0;
+    return 
+    (range_t *)bsearch(&lookup, 
+                       ranges->array, ranges->num_ranges, sizeof(range_t), 
+                       range_cmp_for_search);
+#endif
+}
+
+int get_num_ranges(const range_list_t *ranges)
+{
+    return ranges->num_ranges;
+}
+
+range_t *get_sorted_ranges(const range_list_t *ranges, int *num_ranges) {
+    ASSERT(ranges->is_sorted); /* The range list must be sorted */
+    if (num_ranges) {
+        *num_ranges = ranges->num_ranges;
+    }
+    return ranges->array;
+}
+
+GElf_Off get_last_address(const range_list_t *ranges) {
+    ASSERT(ranges->num_ranges);
+    return 
+    ranges->array[ranges->num_ranges-1].start +
+    ranges->array[ranges->num_ranges-1].length;
+}
+
+static void handle_range_error(range_error_t err, 
+                               range_t *left, range_t *right) {
+    switch (err) {
+    case ERROR_CONTAINS:
+        ERROR("ERROR: section (%lld, %lld bytes) contains "
+              "section (%lld, %lld bytes)\n",
+              left->start, left->length,
+              right->start, right->length);
+        break;
+    case ERROR_OVERLAPS:
+        ERROR("ERROR: Section (%lld, %lld bytes) intersects "
+              "section (%lld, %lld bytes)\n",
+              left->start, left->length,
+              right->start, right->length);
+        break;
+    default:
+        ASSERT(!"Unknown range error code!");
+    }
+
+    FAILIF(1, "Range error.\n");
+}
+
+static void destroy_contiguous_range_info(void *user) {
+    contiguous_range_info_t *info = (contiguous_range_info_t *)user;
+    FREE(info->ranges);
+    FREE(info);
+}
+
+static void handle_contiguous_range_error(range_error_t err, 
+                                          range_t *left, 
+                                          range_t *right)
+{
+    contiguous_range_info_t *left_data = 
+        (contiguous_range_info_t *)left->user;
+    ASSERT(left_data);
+    contiguous_range_info_t *right_data = 
+        (contiguous_range_info_t *)right->user;
+    ASSERT(right_data);
+
+    PRINT("Contiguous-range overlap error.  Printing contained ranges:\n");
+    int cnt;
+    PRINT("\tLeft ranges:\n");
+    for (cnt = 0; cnt < left_data->num_ranges; cnt++) {
+        PRINT("\t\t[%lld, %lld)\n",
+              left_data->ranges[cnt].start,
+              left_data->ranges[cnt].start + left_data->ranges[cnt].length);
+    }
+    PRINT("\tRight ranges:\n");
+    for (cnt = 0; cnt < right_data->num_ranges; cnt++) {
+        PRINT("\t\t[%lld, %lld)\n",
+              right_data->ranges[cnt].start,
+              right_data->ranges[cnt].start + right_data->ranges[cnt].length);
+    }
+
+    handle_range_error(err, left, right);
+}
+
+range_list_t* get_contiguous_ranges(const range_list_t *input)
+{
+    ASSERT(input);
+    FAILIF(!input->is_sorted, 
+           "get_contiguous_ranges(): input range list is not sorted!\n");
+
+    range_list_t* ret = init_range_list();
+    int num_ranges;
+    range_t *ranges = get_sorted_ranges(input, &num_ranges);
+
+    int end_idx = 0;
+    while (end_idx < num_ranges) {
+        int start_idx = end_idx++;
+        int old_end_idx = start_idx;
+        int total_length = ranges[start_idx].length;
+        while (end_idx < num_ranges) {
+            if (ranges[old_end_idx].start + ranges[old_end_idx].length !=
+                ranges[end_idx].start)
+                break;
+            old_end_idx = end_idx++;
+            total_length += ranges[old_end_idx].length;
+        }
+
+        contiguous_range_info_t *user = 
+            (contiguous_range_info_t *)MALLOC(sizeof(contiguous_range_info_t));
+        user->num_ranges = end_idx - start_idx;
+        user->ranges = (range_t *)MALLOC(user->num_ranges * sizeof(range_t));
+        int i;
+        for (i = 0; i < end_idx - start_idx; i++)
+            user->ranges[i] = ranges[start_idx + i];
+        add_unique_range_nosort(ret, 
+                                ranges[start_idx].start,
+                                total_length,
+                                user,
+                                handle_contiguous_range_error,
+                                destroy_contiguous_range_info);
+    }
+
+    return ret;
+}
+
+range_list_t* subtract_ranges(const range_list_t *r, const range_list_t *s)
+{
+    ASSERT(r);  ASSERT(r->is_sorted);
+    ASSERT(s);  ASSERT(s->is_sorted);
+
+    range_list_t *result = init_range_list();
+
+    int r_num_ranges, r_idx;
+    range_t *r_ranges = get_sorted_ranges(r, &r_num_ranges);
+    ASSERT(r_ranges);
+
+    int s_num_ranges, s_idx;
+    range_t *s_ranges = get_sorted_ranges(s, &s_num_ranges);
+    ASSERT(s_ranges);
+
+    s_idx = 0;
+    for (r_idx = 0; r_idx < r_num_ranges; r_idx++) {
+        GElf_Off last_start = r_ranges[r_idx].start;
+        for (; s_idx < s_num_ranges; s_idx++) {
+            if (CONTAINS(&r_ranges[r_idx], &s_ranges[s_idx])) {
+                if (last_start == 
+                    r_ranges[r_idx].start + r_ranges[r_idx].length) {
+                    break;
+                }
+                if (last_start == s_ranges[s_idx].start) {
+                    last_start += s_ranges[s_idx].length;
+                    continue;
+                }
+                INFO("Adding subtracted range [%lld, %lld)\n",
+                     last_start,
+                     s_ranges[s_idx].start);
+                add_unique_range_nosort(
+                    result, 
+                    last_start,
+                    s_ranges[s_idx].start - last_start,
+                    NULL,
+                    NULL,
+                    NULL);
+                last_start = s_ranges[s_idx].start + s_ranges[s_idx].length;
+            } else {
+                ASSERT(!INTERSECT(&r_ranges[r_idx], &s_ranges[s_idx]));
+                break;
+            }
+        } /* while (s_idx < s_num_ranges) */
+    } /* for (r_idx = 0; r_idx < r_num_ranges; r_idx++) */
+
+    return result;
+}
+
+
diff --git a/build/tools/apriori/rangesort.h b/build/tools/apriori/rangesort.h
new file mode 100644 (file)
index 0000000..21db357
--- /dev/null
@@ -0,0 +1,105 @@
+#ifndef RANGESORT_H
+#define RANGESORT_H
+
+/* This implements a simple sorted list of non-overlapping ranges. */
+
+#include <debug.h>
+#include <common.h>
+#include <gelf.h>
+
+typedef enum range_error_t {
+    ERROR_CONTAINS,
+    ERROR_OVERLAPS
+} range_error_t;
+
+typedef struct range_t range_t;
+struct range_t {
+    GElf_Off start;
+    GElf_Off length;
+    void *user;
+    void (*err_fn)(range_error_t, range_t *, range_t *);
+    void (*user_dtor)(void *);
+};
+
+typedef struct range_list_t range_list_t;
+
+range_list_t* init_range_list();
+void destroy_range_list(range_list_t *);
+
+/* Just adds a range to the list. We won't detect whether the range overlaps
+   other ranges or contains them, or is contained by them, till we call 
+   sort_ranges(). */
+void add_unique_range_nosort(range_list_t *ranges, 
+                             GElf_Off start, GElf_Off length, 
+                             void *user,
+                             void (*err_fn)(range_error_t, range_t *, range_t *),
+                             void (*user_dtor)(void * ));
+
+/* Sorts the ranges.  If there are overlapping ranges or ranges that contain
+   other ranges, it will cause the program to exit with a FAIL. */
+range_list_t* sort_ranges(range_list_t *ranges);
+/* Find which range value falls in.  Return that range or NULL if value does
+   not fall within any range. */
+range_t *find_range(range_list_t *ranges, GElf_Off value);
+int get_num_ranges(const range_list_t *ranges);
+range_t *get_sorted_ranges(const range_list_t *ranges, int *num_ranges);
+GElf_Off get_last_address(const range_list_t *ranges);
+
+/* This returns a range_list_t handle that contains ranges composed of the 
+   adjacent ranges of the input range list.  The user data of each range in 
+   the range list is a structure of the type contiguous_range_info_t. 
+   This structure contains an array of pointers to copies of the original 
+   range_t structures comprising each new contiguous range, as well as the 
+   length of that array.  
+
+   NOTE: The input range must be sorted!
+
+   NOTE: destroy_range_list() will take care of releasing the data that it
+   allocates as a result of calling get_contiguous_ranges().  Do not free that
+   data yourself.
+
+   NOTE: the user data of the original range_t structures is simply copied, so 
+   be careful handling it. You can destroy the range_list_t with 
+   destroy_range_list() as usual.  On error, the function does not return--the 
+   program terminates. 
+
+   NOTE: The returned range is not sorted.  You must call sort_ranges() if you
+   need to.
+*/
+
+typedef struct {
+    int num_ranges;
+    range_t *ranges;
+} contiguous_range_info_t;
+
+range_list_t* get_contiguous_ranges(const range_list_t *);
+
+/* The function below takes in two range lists: r and s, and subtracts the 
+   ranges in s from those in r.  For example, if r and s are as follows:
+
+   r = { [0, 10) }
+   s = { [3, 5), [7, 9) }
+
+   Then r - s is { [0, 3), [5, 7), [9, 10) }
+
+   NOTE: Both range lists must be sorted on input.  This is guarded by an 
+         assertion.
+
+   NOTE: Range s must contain ranges, which are fully contained by the span of
+         range r (the span being the interval between the start of the lowest
+         range in r, inclusive, and the end of the highest range in r, 
+         exclusive).
+
+   NOTE: In addition to the requirement above, range s must contain ranges, 
+         each of which is a subrange of one of the ranges of r.
+
+   NOTE: There is no user info associated with the resulting range. 
+
+   NOTE: The resulting range is not sorted.
+
+   Ther returned list must be destroyed with destroy_range_list().
+*/
+
+range_list_t* subtract_ranges(const range_list_t *r, const range_list_t *s);
+
+#endif/*RANGESORT_H*/
diff --git a/build/tools/apriori/source.c b/build/tools/apriori/source.c
new file mode 100644 (file)
index 0000000..69c57c7
--- /dev/null
@@ -0,0 +1,18 @@
+#include <source.h>
+
+void find_section(source_t *source, Elf64_Addr address,
+                  Elf_Scn **scn, 
+                  GElf_Shdr *shdr, 
+                  Elf_Data **data)
+{
+    range_t *range = find_range(source->sorted_sections, address);
+    FAILIF(NULL == range, 
+           "Cannot match address %lld to any range in [%s]!\n",
+           address,
+           source->name);
+    *scn = (Elf_Scn *)range->user;
+    ASSERT(*scn);
+    FAILIF_LIBELF(NULL == gelf_getshdr(*scn, shdr), gelf_getshdr);
+    *data = elf_getdata(*scn, NULL);
+    FAILIF_LIBELF(NULL == *data, elf_getdata);
+}
diff --git a/build/tools/apriori/source.h b/build/tools/apriori/source.h
new file mode 100644 (file)
index 0000000..a5d96bd
--- /dev/null
@@ -0,0 +1,121 @@
+#ifndef SOURCE_H
+#define SOURCE_H
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <libelf.h>
+#include <libebl.h>
+#ifdef ARM_SPECIFIC_HACKS
+    #include <libebl_arm.h>
+#endif/*ARM_SPECIFIC_HACKS*/
+#include <elf.h>
+#include <gelf.h>
+#include <rangesort.h>
+#include <elfcopy.h>
+
+typedef struct source_t source_t;
+
+typedef struct {
+    Elf_Scn *scn;
+    GElf_Shdr shdr;
+    Elf_Data *data;
+    shdr_info_t *info;
+} section_info_t;
+
+typedef struct {
+    GElf_Rel *rels;
+    int num_rels; /* number of relocations that were not finished */
+    int rels_size; /* this is the size of rels[], NOT the number of rels! */
+} unfinished_relocation_t;
+
+typedef struct {
+    int processed;
+    size_t idx; /* index of DT entry in the .dynamic section, if entry has a ptr value */
+    Elf64_Addr addr; /* if DT entry's value is an address, we save it here */
+    size_t sz_idx; /* index of DT entry in the .dynamic section, if entry has a size value */
+    Elf64_Xword size; /* if DT entry's value is a size, we save it here */
+
+    range_list_t *sections; /* list of sections corresponding to this entry */
+    int num_unfinished_relocs; /* this variables is populated by adjust_dynamic_segment_for()
+                                  during the second pass of the prelinker */
+} dt_rel_info_t;
+
+struct source_t {
+    source_t *next;
+
+    char *name;  /* full path name of this executable file */
+    char *output; /* name of the output file or directory */
+    int output_is_dir; /* nonzero if output is a directory, 0 if output is a file */
+    /* ELF-related information: */
+    Elf *oldelf;
+    Elf *elf;
+    /* info[] is an array of structures describing the sections of the new ELF
+       file.  We populate the info[] array in clone_elf(), and use it to
+       adjust the size of the ELF file when we modify the relocation-entry
+       section.
+    */
+    shdr_info_t *shdr_info;
+    GElf_Ehdr old_ehdr_mem; /* store ELF header of original library */
+    GElf_Ehdr ehdr_mem; /* store ELF header of new library */
+    GElf_Phdr *phdr_info;
+    Ebl *ebl;
+    Elf_Data *shstrtab_data;
+    int elf_fd;
+    int newelf_fd; /* fd of output file, -1 if output == NULL */
+       struct stat elf_file_info;
+    GElf_Ehdr elf_hdr, oldelf_hdr;
+    size_t shstrndx;
+    int shnum; /* number of sections */
+    int dry_run; /* 0 if we do not update the files, 1 (default) otherwise */
+
+    section_info_t symtab;
+    section_info_t strtab;
+    section_info_t dynamic;
+    section_info_t hash;
+    section_info_t bss;
+
+    range_list_t *sorted_sections;
+
+    section_info_t *relocation_sections; /* relocation sections in file */
+    int num_relocation_sections; /* number of relocation sections (<= relocation_sections_size) */
+    int relocation_sections_size; /* sice of array -- NOT number of relocs! */
+
+    /* relocation sections that contain relocations that could not be handled.
+       This array is parallel to relocation_sections, and for each entry
+       in that array, it contains a list of relocations that could not be
+       handled.
+    */
+    unfinished_relocation_t *unfinished;
+
+    /* The sections field of these two structuer contains a list of elements
+       of the member variable relocations. */
+    dt_rel_info_t rel;
+    dt_rel_info_t jmprel;
+
+    int num_syms; /* number of symbols in symbol table.  This is the length of
+                     both exports[] and satisfied[] arrays. */
+
+    /* This is an array that contains one element for each library dependency
+       listed in the executable or shared library. */
+    source_t **lib_deps; /* list of library dependencies */
+    int num_lib_deps; /* actual number of library dependencies */
+    int lib_deps_size; /* size of lib_deps array--NOT actual number of deps! */
+
+    /* This is zero for executables.  For shared libraries, it is the address
+          at which the library was prelinked. */
+    unsigned base;
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+       /* When we read in a file, if it has the prelinked tag, we set prelinked
+          to 1 and the prelink address in the tag to prelink_base.  This address
+          must match the value of base that we choose. */
+       int prelinked;
+       long prelink_base; /* valid if prelinked != 0 */
+#endif/*SUPPORT_ANDROID_PRELINK_TAGS*/
+};
+
+extern void find_section(source_t *source, Elf64_Addr address,
+                         Elf_Scn **scn,
+                         GElf_Shdr *shdr,
+                         Elf_Data **data);
+
+#endif/*SOURCE_H*/
diff --git a/build/tools/apriori/tweak.h b/build/tools/apriori/tweak.h
new file mode 100644 (file)
index 0000000..3afedee
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef TWEAK_H\r
+#define TWEAK_H\r
+\r
+#include <source.h>\r
+\r
+/* This function will break up the .bss section into multiple subsegments, \r
+   depending on whether the .bss segment contains copy-relocated symbols.  This\r
+   will produce a nonstandard ELF file (with multiple .bss sections), tht the\r
+   linker will need to know how to handle.  The return value is the number of\r
+   segments that the .bss segment was broken into (zero if the .bss segment was\r
+   not modified. */\r
+\r
+int tweak_bss_if_necessary(source_t *source);\r
+\r
+#endif/*TWEAK_H*/\r
diff --git a/build/tools/atree/Android.mk b/build/tools/atree/Android.mk
new file mode 100644 (file)
index 0000000..d895810
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright 2007 The Android Open Source Project
+#
+# Copies files into the directory structure described by a manifest
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+       atree.cpp \
+       files.cpp \
+       fs.cpp
+
+LOCAL_STATIC_LIBRARIES := \
+       libhost
+LOCAL_C_INCLUDES := build/libs/host/include
+
+LOCAL_MODULE := atree
+
+include $(BUILD_HOST_EXECUTABLE)
+
diff --git a/build/tools/atree/atree.cpp b/build/tools/atree/atree.cpp
new file mode 100644 (file)
index 0000000..aee2b3c
--- /dev/null
@@ -0,0 +1,301 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "options.h"
+#include "files.h"
+#include "fs.h"
+#include <set>
+#include <iostream>
+#include <sstream>
+
+using namespace std;
+
+bool g_debug = false;
+vector<string> g_listFiles;
+vector<string> g_inputBases;
+map<string, string> g_variables;
+string g_outputBase;
+string g_dependency;
+bool g_useHardLinks = false;
+
+const char* USAGE =
+"\n"
+"Usage: atree OPTIONS\n"
+"\n"
+"Options:\n"
+"  -f FILELIST    Specify one or more files containing the\n"
+"                 list of files to copy.\n"
+"  -I INPUTDIR    Specify one or more base directories in\n"
+"                 which to look for the files\n"
+"  -o OUTPUTDIR   Specify the directory to copy all of the\n"
+"                 output files to.\n"
+"  -l             Use hard links instead of copying the files.\n"
+"  -m DEPENDENCY  Output a make-formatted file containing the list.\n"
+"                 of files included.  It sets the variable ATREE_FILES.\n"
+"  -v VAR=VAL     Replaces ${VAR} by VAL when reading input files.\n"
+"\n"
+"FILELIST file format:\n"
+"  The FILELIST files contain the list of files that will end up\n"
+"  in the final OUTPUTDIR.  Atree will look for files in the INPUTDIR\n"
+"  directories in the order they are specified.\n"
+"\n"
+"  In a FILELIST file, comment lines start with a #.  Other lines\n"
+"  are of the format:\n"
+"\n"
+"    DEST\n"
+"    SRC DEST\n"
+"    -SRCPATTERN\n"
+"\n"
+"  DEST should be path relative to the output directory.\n"
+"  If SRC is supplied, the file names can be different.\n"
+"  SRCPATTERN is a pattern for the filenames.\n"
+"\n";
+
+int usage()
+{
+    fwrite(USAGE, strlen(USAGE), 1, stderr);
+    return 1;
+}
+
+static bool
+add_variable(const char* arg) {
+    const char* p = arg;
+    while (*p && *p != '=') p++;
+
+    if (*p == 0 || p == arg || p[1] == 0) {
+        return false;
+    }
+
+    ostringstream var;
+    var << "${" << string(arg, p-arg) << "}";
+    g_variables[var.str()] = string(p+1);
+    return true;
+}
+
+int
+main(int argc, char* const* argv)
+{
+    int err;
+    bool done = false;
+    while (!done) {
+        int opt = getopt(argc, argv, "f:I:o:hlm:v:");
+        switch (opt)
+        {
+            case -1:
+                done = true;
+                break;
+            case 'f':
+                g_listFiles.push_back(string(optarg));
+                break;
+            case 'I':
+                g_inputBases.push_back(string(optarg));
+                break;
+            case 'o':
+                if (g_outputBase.length() != 0) {
+                    fprintf(stderr, "%s: -o may only be supplied once -- "
+                                "-o %s\n", argv[0], optarg);
+                    return usage();
+                }
+                g_outputBase = optarg;
+                break;
+            case 'l':
+                g_useHardLinks = true;
+                break;
+            case 'm':
+                if (g_dependency.length() != 0) {
+                    fprintf(stderr, "%s: -m may only be supplied once -- "
+                                "-m %s\n", argv[0], optarg);
+                    return usage();
+                }
+                g_dependency = optarg;
+                break;
+            case 'v':
+                if (!add_variable(optarg)) {
+                    fprintf(stderr, "%s Invalid expression in '-v %s': "
+                            "expected format is '-v VAR=VALUE'.\n",
+                            argv[0], optarg);
+                    return usage();
+                }
+                break;
+            default:
+            case '?':
+            case 'h':
+                return usage();
+        }
+    }
+    if (optind != argc) {
+        fprintf(stderr, "%s: invalid argument -- %s\n", argv[0], argv[optind]);
+        return usage();
+    }
+
+    if (g_listFiles.size() == 0) {
+        fprintf(stderr, "%s: At least one -f option must be supplied.\n",
+                 argv[0]);
+        return usage();
+    }
+
+    if (g_inputBases.size() == 0) {
+        fprintf(stderr, "%s: At least one -I option must be supplied.\n",
+                 argv[0]);
+        return usage();
+    }
+
+    if (g_outputBase.length() == 0) {
+        fprintf(stderr, "%s: -o option must be supplied.\n", argv[0]);
+        return usage();
+    }
+
+
+#if 0
+    for (vector<string>::iterator it=g_listFiles.begin();
+                                it!=g_listFiles.end(); it++) {
+        printf("-f \"%s\"\n", it->c_str());
+    }
+    for (vector<string>::iterator it=g_inputBases.begin();
+                                it!=g_inputBases.end(); it++) {
+        printf("-I \"%s\"\n", it->c_str());
+    }
+    printf("-o \"%s\"\n", g_outputBase.c_str());
+    if (g_useHardLinks) {
+        printf("-l\n");
+    }
+#endif
+
+    vector<FileRecord> files;
+    vector<FileRecord> more;
+    vector<string> excludes;
+    set<string> directories;
+    set<string> deleted;
+
+    // read file lists
+    for (vector<string>::iterator it=g_listFiles.begin();
+                                it!=g_listFiles.end(); it++) {
+        err = read_list_file(*it, g_variables, &files, &excludes);
+        if (err != 0) {
+            return err;
+        }
+    }
+
+    // look for input files
+    err = 0;
+    for (vector<FileRecord>::iterator it=files.begin();
+                                it!=files.end(); it++) {
+        err |= locate(&(*it), g_inputBases);
+
+    }
+    
+    // expand the directories that we should copy into a list of files
+    for (vector<FileRecord>::iterator it=files.begin();
+                                it!=files.end(); it++) {
+        if (it->sourceIsDir) {
+            err |= list_dir(*it, excludes, &more);
+        }
+    }
+    for (vector<FileRecord>::iterator it=more.begin();
+                                it!=more.end(); it++) {
+        files.push_back(*it);
+    }
+
+    // get the name and modtime of the output files
+    for (vector<FileRecord>::iterator it=files.begin();
+                                it!=files.end(); it++) {
+        stat_out(g_outputBase, &(*it));
+    }
+
+    if (err != 0) {
+        return 1;
+    }
+
+    // gather directories
+    for (vector<FileRecord>::iterator it=files.begin();
+                                it!=files.end(); it++) {
+        if (it->sourceIsDir) {
+            directories.insert(it->outPath);
+        } else {
+            string s = dir_part(it->outPath);
+            if (s != ".") {
+                directories.insert(s);
+            }
+        }
+    }
+
+    // gather files that should become directores and directories that should
+    // become files
+    for (vector<FileRecord>::iterator it=files.begin();
+                                it!=files.end(); it++) {
+        if (it->outMod != 0 && it->sourceIsDir != it->outIsDir) {
+            deleted.insert(it->outPath);
+        }
+    }
+
+    // delete files
+    for (set<string>::iterator it=deleted.begin();
+                                it!=deleted.end(); it++) {
+        if (g_debug) {
+            printf("deleting %s\n", it->c_str());
+        }
+        err = remove_recursively(*it);
+        if (err != 0) {
+            return err;
+        }
+    }
+
+    // make directories
+    for (set<string>::iterator it=directories.begin();
+                                it!=directories.end(); it++) {
+        if (g_debug) {
+            printf("mkdir %s\n", it->c_str());
+        }
+        err = mkdir_recursively(*it);
+        if (err != 0) {
+            return err;
+        }
+    }
+
+    // copy (or link) files
+    for (vector<FileRecord>::iterator it=files.begin();
+                                it!=files.end(); it++) {
+        if (!it->sourceIsDir) {
+            if (g_debug) {
+                printf("copy %s(%ld) ==> %s(%ld)", it->sourcePath.c_str(),
+                    it->sourceMod, it->outPath.c_str(), it->outMod);
+                fflush(stdout);
+            }
+
+            if (it->outMod < it->sourceMod) {
+                err = copy_file(it->sourcePath, it->outPath);
+                if (g_debug) {
+                    printf(" done.\n");
+                }
+                if (err != 0) {
+                    return err;
+                }
+            } else {
+                if (g_debug) {
+                    printf(" skipping.\n");
+                }
+            }
+        }
+    }
+
+    // output the dependency file
+    if (g_dependency.length() != 0) {
+        FILE *f = fopen(g_dependency.c_str(), "w");
+        if (f != NULL) {
+            fprintf(f, "ATREE_FILES := $(ATREE_FILES) \\\n");
+            for (vector<FileRecord>::iterator it=files.begin();
+                                it!=files.end(); it++) {
+                if (!it->sourceIsDir) {
+                    fprintf(f, "%s \\\n", it->sourcePath.c_str());
+                }
+            }
+            fprintf(f, "\n");
+            fclose(f);
+        } else {
+            fprintf(stderr, "error opening manifest file for write: %s\n",
+                    g_dependency.c_str());
+        }
+    }
+
+    return 0;
+}
diff --git a/build/tools/atree/files.cpp b/build/tools/atree/files.cpp
new file mode 100644 (file)
index 0000000..d4866d4
--- /dev/null
@@ -0,0 +1,429 @@
+#include "files.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <fnmatch.h>
+#include <string.h>
+#include <stdlib.h>
+
+static bool
+is_comment_line(const char* p)
+{
+    while (*p && isspace(*p)) {
+        p++;
+    }
+    return *p == '#';
+}
+
+static string
+path_append(const string& base, const string& leaf)
+{
+    string full = base;
+    if (base.length() > 0 && leaf.length() > 0) {
+        full += '/';
+    }
+    full += leaf;
+    return full;
+}
+
+static bool
+is_whitespace_line(const char* p)
+{
+    while (*p) {
+        if (!isspace(*p)) {
+            return false;
+        }
+        p++;
+    }
+    return true;
+}
+
+static bool
+is_exclude_line(const char* p) {
+    while (*p) {
+        if (*p == '-') {
+            return true;
+        }
+        else if (isspace(*p)) {
+            p++;
+        }
+        else {
+            return false;
+        }
+    }
+    return false;
+}
+
+void
+split_line(const char* p, vector<string>* out)
+{
+    const char* q = p;
+    enum { WHITE, TEXT } state = WHITE;
+    while (*p) {
+        if (*p == '#') {
+            break;
+        }
+
+        switch (state)
+        {
+            case WHITE:
+                if (!isspace(*p)) {
+                    q = p;
+                    state = TEXT;
+                }
+                break;
+            case TEXT:
+                if (isspace(*p)) {
+                    if (q != p) {
+                        out->push_back(string(q, p-q));
+                    }
+                    state = WHITE;
+                }
+                break;
+        }
+        p++;
+    }
+    if (state == TEXT) {
+        out->push_back(string(q, p-q));
+    }
+}
+
+static void
+add_file(vector<FileRecord>* files, const string& listFile, int listLine,
+            const string& sourceName, const string& outName)
+{
+    FileRecord rec;
+    rec.listFile = listFile;
+    rec.listLine = listLine;
+    rec.sourceName = sourceName;
+    rec.outName = outName;
+    files->push_back(rec);
+}
+
+static string
+replace_variables(const string& input,
+                  const map<string, string>& variables,
+                  bool* error) {
+    if (variables.empty()) {
+        return input;
+    }
+
+    // Abort if the variable prefix is not found
+    if (input.find("${") == string::npos) {
+        return input;
+    }
+
+    string result = input;
+
+    // Note: rather than be fancy to detect recursive replacements,
+    // we simply iterate till a given threshold is met.
+
+    int retries = 1000;
+    bool did_replace;
+
+    do {
+        did_replace = false;
+        for (map<string, string>::const_iterator it = variables.begin();
+             it != variables.end(); ++it) {
+            string::size_type pos = 0;
+            while((pos = result.find(it->first, pos)) != string::npos) {
+                result = result.replace(pos, it->first.length(), it->second);
+                pos += it->second.length();
+                did_replace = true;
+            }
+        }
+        if (did_replace && --retries == 0) {
+            *error = true;
+            fprintf(stderr, "Recursive replacement detected during variables "
+                    "substitution. Full list of variables is: ");
+
+            for (map<string, string>::const_iterator it = variables.begin();
+                 it != variables.end(); ++it) {
+                fprintf(stderr, "  %s=%s\n",
+                        it->first.c_str(), it->second.c_str());
+            }
+
+            return result;
+        }
+    } while (did_replace);
+
+    return result;
+}
+
+int
+read_list_file(const string& filename,
+               const map<string, string>& variables,
+               vector<FileRecord>* files,
+               vector<string>* excludes)
+{
+    int err = 0;
+    FILE* f = NULL;
+    long size;
+    char* buf = NULL;
+    char *p, *q;
+    int i, lineCount;
+
+    f = fopen(filename.c_str(), "r");
+    if (f == NULL) {
+        fprintf(stderr, "Could not open list file (%s): %s\n",
+                    filename.c_str(), strerror(errno));
+        err = errno;
+        goto cleanup;
+    }
+
+    err = fseek(f, 0, SEEK_END);
+    if (err != 0) {
+        fprintf(stderr, "Could not seek to the end of file %s. (%s)\n",
+                    filename.c_str(), strerror(errno));
+        err = errno;
+        goto cleanup;
+    }
+    
+    size = ftell(f);
+
+    err = fseek(f, 0, SEEK_SET);
+    if (err != 0) {
+        fprintf(stderr, "Could not seek to the beginning of file %s. (%s)\n",
+                    filename.c_str(), strerror(errno));
+        err = errno;
+        goto cleanup;
+    }
+
+    buf = (char*)malloc(size+1);
+    if (buf == NULL) {
+        // (potentially large)
+        fprintf(stderr, "out of memory (%ld)\n", size);
+        err = ENOMEM;
+        goto cleanup;
+    }
+
+    if (1 != fread(buf, size, 1, f)) {
+        fprintf(stderr, "error reading file %s. (%s)\n",
+                    filename.c_str(), strerror(errno));
+        err = errno;
+        goto cleanup;
+    }
+
+    // split on lines
+    p = buf;
+    q = buf+size;
+    lineCount = 0;
+    while (p<q) {
+        if (*p == '\r' || *p == '\n') {
+            *p = '\0';
+            lineCount++;
+        }
+        p++;
+    }
+
+    // read lines
+    p = buf;
+    for (i=0; i<lineCount; i++) {
+        int len = strlen(p);
+        q = p + len + 1;
+        if (is_whitespace_line(p) || is_comment_line(p)) {
+            ;
+        }
+        else if (is_exclude_line(p)) {
+            while (*p != '-') p++;
+            p++;
+            excludes->push_back(string(p));
+        }
+        else {
+            vector<string> words;
+
+            split_line(p, &words);
+
+#if 0
+            printf("[ ");
+            for (size_t k=0; k<words.size(); k++) {
+                printf("'%s' ", words[k].c_str());
+            }
+            printf("]\n");
+#endif
+            
+            if (words.size() == 1) {
+                // pattern: DEST
+                bool error = false;
+                string w0 = replace_variables(words[0], variables, &error);
+                if (error) {
+                    err = 1;
+                    goto cleanup;
+                }
+                add_file(files, filename, i+1, w0, w0);
+            }
+            else if (words.size() == 2) {
+                // pattern: SRC DEST
+                bool error = false;
+                string w0, w1;
+                w0 = replace_variables(words[0], variables, &error);
+                if (!error) {
+                    w1 = replace_variables(words[1], variables, &error);
+                }
+                if (error) {
+                    err = 1;
+                    goto cleanup;
+                }
+                add_file(files, filename, i+1, w0, w1);
+            }
+            else {
+                fprintf(stderr, "%s:%d: bad format: %s\n", filename.c_str(),
+                        i+1, p);
+                err = 1;
+            }
+        }
+        p = q;
+    }
+
+cleanup:
+    if (buf != NULL) {
+        free(buf);
+    }
+    if (f != NULL) {
+        fclose(f);
+    }
+    return err;
+}
+
+
+int
+locate(FileRecord* rec, const vector<string>& search)
+{
+    int err;
+
+    for (vector<string>::const_iterator it=search.begin();
+                it!=search.end(); it++) {
+        string full = path_append(*it, rec->sourceName);
+        struct stat st;
+        err = stat(full.c_str(), &st);
+        if (err == 0) {
+            rec->sourceBase = *it;
+            rec->sourcePath = full;
+            rec->sourceMod = st.st_mtime;
+            rec->sourceIsDir = S_ISDIR(st.st_mode);
+            return 0;
+        }
+    }
+
+    fprintf(stderr, "%s:%d: couldn't locate source file: %s\n",
+                rec->listFile.c_str(), rec->listLine, rec->sourceName.c_str());
+    return 1;
+}
+
+void
+stat_out(const string& base, FileRecord* rec)
+{
+    rec->outPath = path_append(base, rec->outName);
+
+    int err;
+    struct stat st;
+    err = stat(rec->outPath.c_str(), &st);
+    if (err == 0) {
+        rec->outMod = st.st_mtime;
+        rec->outIsDir = S_ISDIR(st.st_mode);
+    } else {
+        rec->outMod = 0;
+        rec->outIsDir = false;
+    }
+}
+
+string
+dir_part(const string& filename)
+{
+    int pos = filename.rfind('/');
+    if (pos <= 0) {
+        return ".";
+    }
+    return filename.substr(0, pos);
+}
+
+static void
+add_more(const string& entry, bool isDir,
+         const FileRecord& rec, vector<FileRecord>*more)
+{
+    FileRecord r;
+    r.listFile = rec.listFile;
+    r.listLine = rec.listLine;
+    r.sourceName = path_append(rec.sourceName, entry);
+    r.sourcePath = path_append(rec.sourceBase, r.sourceName);
+    struct stat st;
+    int err = stat(r.sourcePath.c_str(), &st);
+    if (err == 0) {
+        r.sourceMod = st.st_mtime;
+    }
+    r.sourceIsDir = isDir;
+    r.outName = path_append(rec.outName, entry);
+    more->push_back(r);
+}
+
+static bool
+matches_excludes(const char* file, const vector<string>& excludes)
+{
+    for (vector<string>::const_iterator it=excludes.begin();
+            it!=excludes.end(); it++) {
+        if (0 == fnmatch(it->c_str(), file, FNM_PERIOD)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static int
+list_dir(const string& path, const FileRecord& rec,
+                const vector<string>& excludes,
+                vector<FileRecord>* more)
+{
+    int err;
+
+    string full = path_append(rec.sourceBase, rec.sourceName);
+    full = path_append(full, path);
+
+    DIR *d = opendir(full.c_str());
+    if (d == NULL) {
+        return errno;
+    }
+
+    vector<string> dirs;
+
+    struct dirent *ent;
+    while (NULL != (ent = readdir(d))) {
+        if (0 == strcmp(".", ent->d_name)
+                || 0 == strcmp("..", ent->d_name)) {
+            continue;
+        }
+        if (matches_excludes(ent->d_name, excludes)) {
+            continue;
+        }
+        string entry = path_append(path, ent->d_name);
+#ifdef HAVE_DIRENT_D_TYPE
+               bool is_directory = (ent->d_type == DT_DIR);
+#else
+           // If dirent.d_type is missing, then use stat instead
+               struct stat stat_buf;
+               stat(entry.c_str(), &stat_buf);
+               bool is_directory = S_ISDIR(stat_buf.st_mode);
+#endif
+        add_more(entry, is_directory, rec, more);
+        if (is_directory) {
+            dirs.push_back(entry);
+        }
+    }
+    closedir(d);
+
+    for (vector<string>::iterator it=dirs.begin(); it!=dirs.end(); it++) {
+        list_dir(*it, rec, excludes, more);
+    }
+
+    return 0;
+}
+
+int
+list_dir(const FileRecord& rec, const vector<string>& excludes,
+            vector<FileRecord>* files)
+{
+    return list_dir("", rec, excludes, files);
+}
diff --git a/build/tools/atree/files.h b/build/tools/atree/files.h
new file mode 100644 (file)
index 0000000..6480c98
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef FILES_H
+#define FILES_H
+
+#include <map>
+#include <string>
+#include <vector>
+#include <sys/types.h>
+
+using namespace std;
+
+struct FileRecord
+{
+    string listFile;
+    int listLine;
+
+    string sourceBase;
+    string sourceName;
+    string sourcePath;
+    bool sourceIsDir;
+    time_t sourceMod;
+
+    string outName;
+    string outPath;
+    time_t outMod;
+    bool outIsDir;
+    unsigned int mode;
+};
+
+int read_list_file(const string& filename,
+                   const map<string, string>& variables,
+                   vector<FileRecord>* files,
+                   vector<string>* excludes);
+int locate(FileRecord* rec, const vector<string>& search);
+void stat_out(const string& base, FileRecord* rec);
+string dir_part(const string& filename);
+int list_dir(const FileRecord& rec, const vector<string>& excludes,
+                    vector<FileRecord>* files);
+
+#endif // FILES_H
diff --git a/build/tools/atree/fs.cpp b/build/tools/atree/fs.cpp
new file mode 100644 (file)
index 0000000..9971879
--- /dev/null
@@ -0,0 +1,148 @@
+#include "fs.h"
+#include "files.h"
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string>
+#include <vector>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <host/CopyFile.h>
+
+using namespace std;
+
+static bool
+is_dir(const string& path)
+{
+    int err;
+    struct stat st;
+    err = stat(path.c_str(), &st);
+    return err != 0 || S_ISDIR(st.st_mode);
+}
+
+static int
+remove_file(const string& path)
+{
+    int err = unlink(path.c_str());
+    if (err != 0) {
+        fprintf(stderr, "error deleting file %s (%s)\n", path.c_str(),
+                strerror(errno));
+        return errno;
+    }
+    return 0;
+}
+
+int
+remove_recursively(const string& path)
+{
+    int err;
+
+    if (is_dir(path)) {
+        DIR *d = opendir(path.c_str());
+        if (d == NULL) {
+            fprintf(stderr, "error getting directory contents %s (%s)\n",
+                    path.c_str(), strerror(errno));
+            return errno;
+        }
+
+        vector<string> files;
+        vector<string> dirs;
+
+        struct dirent *ent;
+        while (NULL != (ent = readdir(d))) {
+            if (0 == strcmp(".", ent->d_name)
+                    || 0 == strcmp("..", ent->d_name)) {
+                continue;
+            }
+            string full = path;
+            full += '/';
+            full += ent->d_name;
+#ifdef HAVE_DIRENT_D_TYPE
+            bool is_directory = (ent->d_type == DT_DIR);
+#else
+               // If dirent.d_type is missing, then use stat instead
+                       struct stat stat_buf;
+                       stat(full.c_str(), &stat_buf);
+                       bool is_directory = S_ISDIR(stat_buf.st_mode);
+#endif
+            if (is_directory) {
+                dirs.push_back(full);
+            } else {
+                files.push_back(full);
+            }
+        }
+        closedir(d);
+
+        for (vector<string>::iterator it=files.begin(); it!=files.end(); it++) {
+            err = remove_file(*it);
+            if (err != 0) {
+                return err;
+            }
+        }
+
+        for (vector<string>::iterator it=dirs.begin(); it!=dirs.end(); it++) {
+            err = remove_recursively(*it);
+            if (err != 0) {
+                return err;
+            }
+        }
+
+        err = rmdir(path.c_str());
+        if (err != 0) {
+            fprintf(stderr, "error deleting directory %s (%s)\n", path.c_str(),
+                    strerror(errno));
+            return errno;
+        }
+        return 0;
+    } else {
+        return remove_file(path);
+    }
+}
+
+int
+mkdir_recursively(const string& path)
+{
+    int err;
+    size_t pos = 0;
+    // For absolute pathnames, that starts with leading '/'
+    // use appropriate initial value.
+    if (path.length() != 0 and path[0] == '/') pos++;
+
+    while (true) {
+        pos = path.find('/', pos);
+        string p = path.substr(0, pos);
+        struct stat st;
+        err = stat(p.c_str(), &st);
+        if (err != 0) {
+            err = mkdir(p.c_str(), 0770);
+            if (err != 0) {
+                fprintf(stderr, "can't create directory %s (%s)\n",
+                        path.c_str(), strerror(errno));
+                return errno;
+            }
+        }
+        else if (!S_ISDIR(st.st_mode)) {
+            fprintf(stderr, "can't create directory %s because %s is a file.\n",
+                        path.c_str(), p.c_str());
+            return 1;
+        }
+        pos++;
+        if (p == path) {
+            return 0;
+        }
+    }
+}
+
+int
+copy_file(const string& src, const string& dst)
+{
+    int err;
+
+    err = copyFile(src.c_str(), dst.c_str(),
+                    COPY_NO_DEREFERENCE | COPY_FORCE | COPY_PERMISSIONS);
+    return err;
+}
diff --git a/build/tools/atree/fs.h b/build/tools/atree/fs.h
new file mode 100644 (file)
index 0000000..4080880
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef FS_H
+#define FS_H
+
+#include <string>
+
+using namespace std;
+
+int remove_recursively(const string& path);
+int mkdir_recursively(const string& path);
+int copy_file(const string& src, const string& dst);
+
+#endif // FS_H
diff --git a/build/tools/atree/options.h b/build/tools/atree/options.h
new file mode 100644 (file)
index 0000000..a227d0f
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef OPTIONS_H
+#define OPTIONS_H
+
+#include <string>
+#include <vector>
+
+using namespace std;
+
+extern vector<string> g_listFiles;
+extern vector<string> g_inputBases;
+extern string g_outputBase;
+extern bool g_useHardLinks;
+
+#endif // OPTIONS_H
diff --git a/build/tools/bin2asm/Android.mk b/build/tools/bin2asm/Android.mk
new file mode 100644 (file)
index 0000000..4522a20
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    icudata.c
+
+LOCAL_MODULE := icudata
+
+include $(BUILD_HOST_EXECUTABLE)
+
diff --git a/build/tools/bin2asm/data b/build/tools/bin2asm/data
new file mode 100644 (file)
index 0000000..3be865f
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Convert a data file into a .S file suitable for assembly.
+ * This reads from stdin and writes to stdout and takes a single
+ * argument for the name of the symbol in the assembly file.
+ */
+
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+    unsigned char buf[4096];
+    size_t amt;
+    size_t i;
+    int col = 0;
+    char *name = argv[1];
+
+    printf("\
+#ifdef __APPLE_CC__\n\
+/*\n\
+ * The mid-2007 version of gcc that ships with Macs requires a\n\
+ * comma on the .section line, but the rest of the world thinks\n\
+ * that's a syntax error. It also wants globals to be explicitly\n\
+ * prefixed with \"_\" as opposed to modern gccs that do the\n\
+ * prefixing for you.\n\
+ */\n\
+.globl _%s\n\
+       .section .rodata,\n\
+       .align 8\n\
+_%s:\n\
+#else\n\
+.globl %s\n\
+       .section .rodata\n\
+       .align 8\n\
+%s:\n\
+#endif\n\
+", name, name, name, name);
+    
+    while (! feof(stdin)) {
+        amt = fread(buf, 1, sizeof(buf), stdin);
+        for (i = 0; i < amt; i++) {
+            printf((col == 0) ? ".byte %3d" : ",%3d", buf[i]);
+            col++;
+            if (col == 16) {
+                printf("\n");
+                col = 0;
+            }
+        }
+    }
+
+    if (col != 0) {
+        printf("\n");
+    }
+}
diff --git a/build/tools/bin2asm/icudata.c b/build/tools/bin2asm/icudata.c
new file mode 100644 (file)
index 0000000..ecd1b4b
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Convert a data file into a .S file suitable for assembly.
+ * This reads from stdin and writes to stdout and takes a single
+ * argument for the name of the symbol in the assembly file.
+ */
+
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+    unsigned char buf[4096];
+    size_t amt;
+    size_t i;
+    int col = 0;
+    char *name;
+
+    if (argc != 2) {
+        fprintf(stderr, "usage: %s NAME < DAT_FILE > ASM_FILE\n", argv[0]);
+        for (i=0; i<argc; i++) {
+            fprintf(stderr, " '%s'", argv[i]);
+        }
+        fprintf(stderr, "\n");
+        return 1;
+    }
+    
+    name = argv[1];
+
+    printf("\
+#ifdef __APPLE_CC__\n\
+/*\n\
+ * The mid-2007 version of gcc that ships with Macs requires a\n\
+ * comma on the .section line, but the rest of the world thinks\n\
+ * that's a syntax error. It also wants globals to be explicitly\n\
+ * prefixed with \"_\" as opposed to modern gccs that do the\n\
+ * prefixing for you.\n\
+ */\n\
+.globl _%s\n\
+       .section .rodata,\n\
+       .align 8\n\
+_%s:\n\
+#else\n\
+.globl %s\n\
+       .section .rodata\n\
+       .align 8\n\
+%s:\n\
+#endif\n\
+", name, name, name, name);
+    
+    while (! feof(stdin)) {
+        amt = fread(buf, 1, sizeof(buf), stdin);
+        for (i = 0; i < amt; i++) {
+            if (col == 0) {
+                printf(".byte ");
+            }
+            printf("0x%02x", buf[i]);
+            col++;
+            if (col == 16) {
+                printf("\n");
+                col = 0;
+            } else if (col % 4 == 0) {
+                printf(", ");
+            } else {
+                printf(",");
+            }
+        }
+    }
+
+    if (col != 0) {
+        printf("\n");
+    }
+
+    return 0;
+}
diff --git a/build/tools/buildinfo.sh b/build/tools/buildinfo.sh
new file mode 100644 (file)
index 0000000..6c85149
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+echo "# begin build properties"
+echo "# autogenerated by buildinfo.sh"
+
+echo "ro.build.id=$BUILD_ID"
+echo "ro.build.display.id=$BUILD_DISPLAY_ID"
+echo "ro.build.version.incremental=$BUILD_NUMBER"
+echo "ro.build.version.sdk=$PLATFORM_SDK_VERSION"
+echo "ro.build.version.codename=$PLATFORM_VERSION_CODENAME"
+echo "ro.build.version.release=$PLATFORM_VERSION"
+echo "ro.build.date=`date`"
+echo "ro.build.date.utc=`date +%s`"
+echo "ro.build.type=$TARGET_BUILD_TYPE"
+echo "ro.build.user=$USER"
+echo "ro.build.host=`hostname`"
+echo "ro.build.tags=$BUILD_VERSION_TAGS"
+echo "ro.product.model=$PRODUCT_MODEL"
+echo "ro.product.brand=$PRODUCT_BRAND"
+echo "ro.product.name=$PRODUCT_NAME"
+echo "ro.product.device=$TARGET_DEVICE"
+echo "ro.product.board=$TARGET_BOOTLOADER_BOARD_NAME"
+echo "ro.product.cpu.abi=$TARGET_CPU_ABI"
+if [ -n "$TARGET_CPU_ABI2" ] ; then
+  echo "ro.product.cpu.abi2=$TARGET_CPU_ABI2"
+fi
+echo "ro.product.manufacturer=$PRODUCT_MANUFACTURER"
+echo "ro.product.locale.language=$PRODUCT_DEFAULT_LANGUAGE"
+echo "ro.product.locale.region=$PRODUCT_DEFAULT_REGION"
+echo "ro.wifi.channels=$PRODUCT_DEFAULT_WIFI_CHANNELS"
+echo "ro.board.platform=$TARGET_BOARD_PLATFORM"
+
+echo "# ro.build.product is obsolete; use ro.product.device"
+echo "ro.build.product=$TARGET_DEVICE"
+
+echo "# Do not try to parse ro.build.description or .fingerprint"
+echo "ro.build.description=$PRIVATE_BUILD_DESC"
+echo "ro.build.fingerprint=$BUILD_FINGERPRINT"
+
+echo "# end build properties"
diff --git a/build/tools/check_builds.sh b/build/tools/check_builds.sh
new file mode 100644 (file)
index 0000000..fd380dd
--- /dev/null
@@ -0,0 +1,92 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Usage:
+#
+# Source this file into your environment.  Then:
+#
+#    $ golden_builds sdk-sdk generic-eng generic-userdebug dream-eng
+# 
+# will build a set of combos.  This might take a while.  Then you can
+# go make changes, and run:
+#
+#    $ check_builds sdk-sdk generic-eng generic-userdebug dream-eng
+#
+# Go get dinner, and when you get back, there will be a file
+# test-builds/sizes.html that has a pretty chart of which files are
+# in which tree, and how big they are.  In that chart, cells for files
+# that are missing are red, and rows where the file sizes are not all
+# the same will be blue.
+#
+
+TEST_BUILD_DIR=test-builds
+
+function do_builds
+{
+    PREFIX=$1
+    shift
+    while [ -n "$1" ]
+    do
+        rm -rf $TEST_BUILD_DIR/$PREFIX-$1
+        make PRODUCT-$(echo $1 | sed "s/-.*//" )-installclean
+        make -j6 PRODUCT-$1 dist DIST_DIR=$TEST_BUILD_DIR/$PREFIX-$1
+        if [ $? -ne 0 ] ; then
+            echo FAILED
+            return
+        fi
+        shift
+    done
+}
+
+function golden_builds
+{
+    rm -rf $TEST_BUILD_DIR/golden-* $TEST_BUILD_DIR/dist-*
+    do_builds golden "$@"
+}
+
+function compare_builds
+{
+    local inputs=
+    while [ -n "$1" ]
+    do
+        inputs="$inputs $TEST_BUILD_DIR/golden-$1/installed-files.txt"
+        inputs="$inputs $TEST_BUILD_DIR/dist-$1/installed-files.txt"
+        shift
+    done
+    build/tools/compare_fileslist.py $inputs > $TEST_BUILD_DIR/sizes.html
+}
+
+function check_builds
+{
+    rm -rf $TEST_BUILD_DIR/dist-*
+    do_builds dist "$@"
+    compare_builds "$@"
+}
+
+function diff_builds
+{
+    local inputs=
+    while [ -n "$1" ]
+    do
+        diff $TEST_BUILD_DIR/golden-$1/installed-files.txt $TEST_BUILD_DIR/dist-$1/installed-files.txt &> /dev/null
+        if [ $? != 0 ]; then
+            echo =========== $1 ===========
+            diff $TEST_BUILD_DIR/golden-$1/installed-files.txt $TEST_BUILD_DIR/dist-$1/installed-files.txt
+        fi
+        shift
+    done
+    build/tools/compare_fileslist.py $inputs > $TEST_BUILD_DIR/sizes.html
+}
+
diff --git a/build/tools/check_prereq/Android.mk b/build/tools/check_prereq/Android.mk
new file mode 100644 (file)
index 0000000..abedff6
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_SRC_FILES := check_prereq.c
+LOCAL_MODULE := check_prereq
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_MODULE_TAGS := eng
+LOCAL_C_INCLUDES +=
+LOCAL_STATIC_LIBRARIES += libcutils libc
+
+include $(BUILD_EXECUTABLE)
+
+endif  # !TARGET_SIMULATOR
+
diff --git a/build/tools/check_prereq/check_prereq.c b/build/tools/check_prereq/check_prereq.c
new file mode 100644 (file)
index 0000000..d7b8918
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/system_properties.h>
+#include <cutils/properties.h>
+
+// Compare the timestamp of the new build (passed on the command line)
+// against the current value of ro.build.date.utc.  Exit successfully
+// if the new build is newer than the current build (or if the
+// timestamps are the same).
+int main(int argc, char** argv) {
+  if (argc != 2) {
+ usage:
+    fprintf(stderr, "usage: %s <timestamp>\n", argv[0]);
+    return 2;
+  }
+
+  char value[PROPERTY_VALUE_MAX];
+  char* default_value = "0";
+
+  property_get("ro.build.date.utc", value, default_value);
+
+  long current = strtol(value, NULL, 10);
+  char* end;
+  long install = strtol(argv[1], &end, 10);
+
+  printf("current build time: [%ld]  new build time: [%ld]\n",
+         current, install);
+
+  return (*end == 0 && current > 0 && install >= current) ? 0 : 1;
+}
diff --git a/build/tools/compare_fileslist.py b/build/tools/compare_fileslist.py
new file mode 100644 (file)
index 0000000..1f507d8
--- /dev/null
@@ -0,0 +1,106 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import cgi, os, string, sys
+
+def IsDifferent(row):
+  val = None
+  for v in row:
+    if v:
+      if not val:
+        val = v
+      else:
+        if val != v:
+          return True
+  return False
+
+def main(argv):
+  inputs = argv[1:]
+  data = {}
+  index = 0
+  for input in inputs:
+    f = file(input, "r")
+    lines = f.readlines()
+    f.close()
+    lines = map(string.split, lines)
+    lines = map(lambda (x,y): (y,int(x)), lines)
+    for fn,sz in lines:
+      if not data.has_key(fn):
+        data[fn] = {}
+      data[fn][index] = sz
+    index = index + 1
+  rows = []
+  for fn,sizes in data.iteritems():
+    row = [fn]
+    for i in range(0,index):
+      if sizes.has_key(i):
+        row.append(sizes[i])
+      else:
+        row.append(None)
+    rows.append(row)
+  rows = sorted(rows, key=lambda x: x[0])
+  print """<html>
+    <head>
+      <style type="text/css">
+        .fn, .sz, .z, .d {
+          padding-left: 10px;
+          padding-right: 10px;
+        }
+        .sz, .z, .d {
+          text-align: right;
+        }
+        .fn {
+          background-color: #ffffdd;
+        }
+        .sz {
+          background-color: #ffffcc;
+        }
+        .z {
+          background-color: #ffcccc;
+        }
+        .d {
+          background-color: #99ccff;
+        }
+      </style>
+    </head>
+    <body>
+  """
+  print "<table>"
+  print "<tr>"
+  for input in inputs:
+    combo = input.split(os.path.sep)[1]
+    print "  <td class='fn'>%s</td>" % cgi.escape(combo)
+  print "</tr>"
+
+  for row in rows:
+    print "<tr>"
+    for sz in row[1:]:
+      if not sz:
+        print "  <td class='z'>&nbsp;</td>"
+      elif IsDifferent(row[1:]):
+        print "  <td class='d'>%d</td>" % sz
+      else:
+        print "  <td class='sz'>%d</td>" % sz
+    print "  <td class='fn'>%s</td>" % cgi.escape(row[0])
+    print "</tr>"
+  print "</table>"
+  print "</body></html>"
+
+if __name__ == '__main__':
+  main(sys.argv)
+
+
diff --git a/build/tools/droiddoc/Android.mk b/build/tools/droiddoc/Android.mk
new file mode 100644 (file)
index 0000000..d2d7a95
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(LOCAL_PATH)/src/Android.mk
+
diff --git a/build/tools/droiddoc/NOTICE b/build/tools/droiddoc/NOTICE
new file mode 100644 (file)
index 0000000..3f1b1bb
--- /dev/null
@@ -0,0 +1,45 @@
+
+Copyright (C) 2008 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
+======================================================================
+
+jQuery 1.2.6 - New Wave Javascript
+
+Copyright (c) 2008 John Resig (jquery.com)
+Dual licensed under the MIT (MIT-LICENSE.txt)
+and GPL (GPL-LICENSE.txt) licenses.
+
+Copyright (c) 2009 John Resig, http://jquery.com/
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/build/tools/droiddoc/src/Android.mk b/build/tools/droiddoc/src/Android.mk
new file mode 100644 (file)
index 0000000..30270b5
--- /dev/null
@@ -0,0 +1,69 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    AnnotationInstanceInfo.java \
+    AnnotationValueInfo.java \
+       AttributeInfo.java \
+       AttrTagInfo.java \
+       ClassInfo.java \
+       DroidDoc.java \
+       ClearPage.java \
+       Comment.java \
+       ContainerInfo.java \
+       Converter.java \
+       DocFile.java \
+       DocInfo.java \
+       Errors.java \
+       FieldInfo.java \
+       Hierarchy.java \
+       InheritedTags.java \
+       KeywordEntry.java \
+    LinkReference.java \
+       LiteralTagInfo.java \
+       MemberInfo.java \
+       MethodInfo.java \
+       NavTree.java \
+       PackageInfo.java \
+       ParamTagInfo.java \
+       ParameterInfo.java \
+       ParsedTagInfo.java \
+       Proofread.java \
+       SampleCode.java \
+       SampleTagInfo.java \
+    Scoped.java \
+       SeeTagInfo.java \
+       SinceTagger.java \
+       Sorter.java \
+       SourcePositionInfo.java \
+    Stubs.java \
+       TagInfo.java \
+    TextTagInfo.java \
+       ThrowsTagInfo.java \
+       TodoFile.java \
+       TypeInfo.java
+
+LOCAL_JAVA_LIBRARIES := \
+       apicheck \
+       clearsilver
+
+LOCAL_CLASSPATH := \
+       $(HOST_JDK_TOOLS_JAR)
+
+LOCAL_MODULE:= droiddoc
+
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/build/tools/droiddoc/src/AnnotationInstanceInfo.java b/build/tools/droiddoc/src/AnnotationInstanceInfo.java
new file mode 100644 (file)
index 0000000..c4abc7e
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class AnnotationInstanceInfo
+{
+    private ClassInfo mType;
+    private AnnotationValueInfo[] mElementValues;
+
+    public AnnotationInstanceInfo(ClassInfo type, AnnotationValueInfo[] elementValues)
+    {
+        mType = type;
+        mElementValues = elementValues;
+    }
+
+    ClassInfo type()
+    {
+        return mType;
+    }
+
+    AnnotationValueInfo[] elementValues()
+    {
+        return mElementValues;
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder str = new StringBuilder();
+        str.append("@");
+        str.append(mType.qualifiedName());
+        str.append("(");
+        AnnotationValueInfo[] values = mElementValues;
+        final int N = values.length;
+        for (int i=0; i<N; i++) {
+            AnnotationValueInfo value = values[i];
+            str.append(value.element().name());
+            str.append("=");
+            str.append(value.valueString());
+            if (i != N-1) {
+                str.append(",");
+            }
+        }
+        str.append(")");
+        return str.toString();
+    }
+}
+
diff --git a/build/tools/droiddoc/src/AnnotationValueInfo.java b/build/tools/droiddoc/src/AnnotationValueInfo.java
new file mode 100644 (file)
index 0000000..a2d869a
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class AnnotationValueInfo
+{
+    private Object mValue;
+    private String mString;
+    private MethodInfo mElement;
+
+    public AnnotationValueInfo(MethodInfo element)
+    {
+        mElement = element;
+    }
+
+    public void init(Object value)
+    {
+        mValue = value;
+    }
+
+    public MethodInfo element()
+    {
+        return mElement;
+    }
+
+    public Object value()
+    {
+        return mValue;
+    }
+
+    public String valueString()
+    {
+        Object v = mValue;
+        if (v instanceof TypeInfo) {
+            return ((TypeInfo)v).fullName();
+        }
+        else if (v instanceof FieldInfo) {
+            StringBuilder str = new StringBuilder();
+            FieldInfo f = (FieldInfo)v;
+            str.append(f.containingClass().qualifiedName());
+            str.append('.');
+            str.append(f.name());
+            return str.toString();
+        }
+        else if (v instanceof AnnotationInstanceInfo) {
+            return v.toString();
+        }
+        else if (v instanceof AnnotationValueInfo[]) {
+            StringBuilder str = new StringBuilder();
+            AnnotationValueInfo[] array = (AnnotationValueInfo[])v;
+            final int N = array.length;
+            str.append("{");
+            for (int i=0; i<array.length; i++) {
+                str.append(array[i].valueString());
+                if (i != N-1) {
+                    str.append(",");
+                }
+            }
+            str.append("}");
+            return str.toString();
+        }
+        else {
+            return FieldInfo.constantLiteralValue(v);
+        }
+    }
+}
+
diff --git a/build/tools/droiddoc/src/AttrTagInfo.java b/build/tools/droiddoc/src/AttrTagInfo.java
new file mode 100644 (file)
index 0000000..7f1b4d9
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+
+
+public class AttrTagInfo extends TagInfo
+{
+    private static final String REF_COMMAND = "ref";
+    private static final String NAME_COMMAND = "name";
+    private static final String DESCRIPTION_COMMAND = "description";
+    private static final Pattern TEXT = Pattern.compile("(\\S+)\\s*(.*)", Pattern.DOTALL);
+    private static final Pattern NAME_TEXT = Pattern.compile("(\\S+)(.*)",
+                                                Pattern.DOTALL);
+
+    private ContainerInfo mBase;
+    private String mCommand;
+
+    // if mCommand == "ref"
+    private FieldInfo mRefField;
+    private AttributeInfo mAttrInfo;
+
+    // if mCommand == "name"
+    private String mAttrName;
+
+    // if mCommand == "description"
+    private Comment mDescrComment;
+
+    AttrTagInfo(String name, String kind, String text, ContainerInfo base,
+            SourcePositionInfo position)
+    {
+        super(name, kind, text, position);
+        mBase = base;
+
+        parse(text, base, position);
+    }
+
+    void parse(String text, ContainerInfo base, SourcePositionInfo position) {
+        Matcher m;
+
+        m = TEXT.matcher(text);
+        if (!m.matches()) {
+            Errors.error(Errors.BAD_ATTR_TAG, position, "Bad @attr tag: " + text);
+            return;
+        }
+
+        String command = m.group(1);
+        String more = m.group(2);
+
+        if (REF_COMMAND.equals(command)) {
+            String ref = more.trim();
+            LinkReference linkRef = LinkReference.parse(ref, mBase, position, false);
+            if (!linkRef.good) {
+                Errors.error(Errors.BAD_ATTR_TAG, position, "Unresolved @attr ref: " + ref);
+                return;
+            }
+            if (!(linkRef.memberInfo instanceof FieldInfo)) {
+                Errors.error(Errors.BAD_ATTR_TAG, position, "@attr must be a field: " + ref);
+                return;
+            }
+            mCommand = command;
+            mRefField = (FieldInfo)linkRef.memberInfo;
+        }
+        else if (NAME_COMMAND.equals(command)) {
+            m = NAME_TEXT.matcher(more);
+            if (!m.matches() || m.group(2).trim().length() != 0) {
+                Errors.error(Errors.BAD_ATTR_TAG, position, "Bad @attr name tag: " + more);
+                return;
+            }
+            mCommand = command;
+            mAttrName = m.group(1);
+        }
+        else if (DESCRIPTION_COMMAND.equals(command)) {
+            mCommand = command;
+            mDescrComment = new Comment(more, base, position);
+        }
+        else {
+            Errors.error(Errors.BAD_ATTR_TAG, position, "Bad @attr command: " + command);
+        }
+    }
+
+    public FieldInfo reference() {
+        return REF_COMMAND.equals(mCommand) ? mRefField : null;
+    }
+
+    @Override
+    public String name() {
+        return NAME_COMMAND.equals(mCommand) ? mAttrName : null;
+    }
+
+    public Comment description() {
+        return DESCRIPTION_COMMAND.equals(mCommand) ? mDescrComment : null;
+    }
+
+    @Override
+    public void makeHDF(HDF data, String base)
+    {
+        super.makeHDF(data, base);
+    }
+
+    public void setAttribute(AttributeInfo info) {
+        mAttrInfo = info;
+    }
+
+    public static void makeReferenceHDF(HDF data, String base, AttrTagInfo[] tags)
+    {
+        int i=0;
+        for (AttrTagInfo t: tags) {
+            if (REF_COMMAND.equals(t.mCommand)) {
+                if (t.mAttrInfo == null) {
+                    String msg = "ERROR: unlinked attr: " + t.mRefField.name();
+                    if (false) {
+                        System.out.println(msg);
+                    } else {
+                        throw new RuntimeException(msg);
+                    }
+                } else {
+                    data.setValue(base + "." + i + ".name", t.mAttrInfo.name());
+                    data.setValue(base + "." + i + ".href", t.mAttrInfo.htmlPage());
+                    i++;
+                }
+            }
+        }
+    }
+
+}
diff --git a/build/tools/droiddoc/src/AttributeInfo.java b/build/tools/droiddoc/src/AttributeInfo.java
new file mode 100644 (file)
index 0000000..a24106b
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.ArrayList;
+import java.util.Comparator;
+
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+
+public class AttributeInfo {
+    public static final Comparator<AttributeInfo> comparator = new Comparator<AttributeInfo>() {
+        public int compare(AttributeInfo a, AttributeInfo b) {
+            return a.name().compareTo(b.name());
+        }
+    };
+    
+    public FieldInfo attrField;
+    public ArrayList<MethodInfo> methods = new ArrayList<MethodInfo>();
+    
+    private ClassInfo mClass;
+    private String mName;
+    private Comment mComment;
+
+    public AttributeInfo(ClassInfo cl, FieldInfo f) {
+        mClass = cl;
+        attrField = f;
+    }
+
+    public String name() {
+        if (mName == null) {
+            for (AttrTagInfo comment: attrField.comment().attrTags()) {
+                String n = comment.name();
+                if (n != null) {
+                    mName = n;
+                    return n;
+                }
+            }
+        }
+        return mName;
+    }
+
+    public Comment comment() {
+        if (mComment == null) {
+            for (AttrTagInfo attr: attrField.comment().attrTags()) {
+                Comment c = attr.description();
+                if (c != null) {
+                    mComment = c;
+                    return c;
+                }
+            }
+        }
+        if (mComment == null) {
+            return new Comment("", mClass, new SourcePositionInfo());
+        }
+        return mComment;
+    }
+    
+    public String anchor() {
+        return "attr_" + name();
+    }
+    public String htmlPage() {
+        return mClass.htmlPage() + "#" + anchor();
+    }
+
+    public void makeHDF(HDF data, String base) {
+        data.setValue(base + ".name", name());
+        data.setValue(base + ".anchor", anchor());
+        data.setValue(base + ".href", htmlPage());
+        data.setValue(base + ".R.name", attrField.name());
+        data.setValue(base + ".R.href", attrField.htmlPage());
+        TagInfo.makeHDF(data, base + ".deprecated", attrField.comment().deprecatedTags());
+        TagInfo.makeHDF(data, base + ".shortDescr", comment().briefTags());
+        TagInfo.makeHDF(data, base + ".descr", comment().tags());
+
+        int i=0;
+        for (MethodInfo m: methods) {
+            String s = base + ".methods." + i;
+            data.setValue(s + ".href", m.htmlPage());
+            data.setValue(s + ".name", m.name() + m.prettySignature());
+        }
+    }
+
+    public boolean checkLevel() {
+        return attrField.checkLevel();
+    }
+}
+
diff --git a/build/tools/droiddoc/src/ClassInfo.java b/build/tools/droiddoc/src/ClassInfo.java
new file mode 100644 (file)
index 0000000..f3f11de
--- /dev/null
@@ -0,0 +1,1464 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.sun.javadoc.*;
+import com.sun.tools.doclets.*;
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+import java.util.*;
+import java.io.*;
+
+public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Scoped
+{
+    public static final Comparator<ClassInfo> comparator = new Comparator<ClassInfo>() {
+        public int compare(ClassInfo a, ClassInfo b) {
+            return a.name().compareTo(b.name());
+        }
+    };
+
+    public static final Comparator<ClassInfo> qualifiedComparator = new Comparator<ClassInfo>() {
+        public int compare(ClassInfo a, ClassInfo b) {
+            return a.qualifiedName().compareTo(b.qualifiedName());
+        }
+    };
+
+    public ClassInfo(
+            ClassDoc cl,
+            String rawCommentText, SourcePositionInfo position,
+            boolean isPublic, boolean isProtected, boolean isPackagePrivate,
+            boolean isPrivate, boolean isStatic,
+            boolean isInterface, boolean isAbstract, boolean isOrdinaryClass,
+            boolean isException, boolean isError, boolean isEnum, boolean isAnnotation,
+            boolean isFinal, boolean isIncluded, String name,
+            String qualifiedName, String qualifiedTypeName, boolean isPrimitive)
+    {
+        super(rawCommentText, position);
+
+        mClass = cl;
+        mIsPublic = isPublic;
+        mIsProtected = isProtected;
+        mIsPackagePrivate = isPackagePrivate;
+        mIsPrivate = isPrivate;
+        mIsStatic = isStatic;
+        mIsInterface = isInterface;
+        mIsAbstract = isAbstract;
+        mIsOrdinaryClass = isOrdinaryClass;
+        mIsException = isException;
+        mIsError = isError;
+        mIsEnum = isEnum;
+        mIsAnnotation = isAnnotation;
+        mIsFinal = isFinal;
+        mIsIncluded = isIncluded;
+        mName = name;
+        mQualifiedName = qualifiedName;
+        mQualifiedTypeName = qualifiedTypeName;
+        mIsPrimitive = isPrimitive;
+        mNameParts = name.split("\\.");
+    }
+
+    public void init(TypeInfo typeInfo, ClassInfo[] interfaces, TypeInfo[] interfaceTypes,
+            ClassInfo[] innerClasses,
+            MethodInfo[] constructors, MethodInfo[] methods, MethodInfo[] annotationElements,
+            FieldInfo[] fields, FieldInfo[] enumConstants,
+            PackageInfo containingPackage, ClassInfo containingClass,
+            ClassInfo superclass, TypeInfo superclassType, AnnotationInstanceInfo[] annotations)
+    {
+        mTypeInfo = typeInfo;
+        mRealInterfaces = interfaces;
+        mRealInterfaceTypes = interfaceTypes;
+        mInnerClasses = innerClasses;
+        mAllConstructors = constructors;
+        mAllSelfMethods = methods;
+        mAnnotationElements = annotationElements;
+        mAllSelfFields = fields;
+        mEnumConstants = enumConstants;
+        mContainingPackage = containingPackage;
+        mContainingClass = containingClass;
+        mRealSuperclass = superclass;
+        mRealSuperclassType = superclassType;
+        mAnnotations = annotations;
+
+        // after providing new methods and new superclass info,clear any cached
+        // lists of self + superclass methods, ctors, etc.
+        mSuperclassInit = false;
+        mConstructors = null;
+        mMethods = null;
+        mSelfMethods = null;
+        mFields = null;
+        mSelfFields = null;
+        mSelfAttributes = null;
+        mDeprecatedKnown = false;
+
+        Arrays.sort(mEnumConstants, FieldInfo.comparator);
+        Arrays.sort(mInnerClasses, ClassInfo.comparator);
+    }
+
+    public void init2() {
+        // calling this here forces the AttrTagInfo objects to be linked to the AttribtueInfo
+        // objects
+        selfAttributes();
+    }
+
+    public void init3(TypeInfo[] types, ClassInfo[] realInnerClasses){
+      mTypeParameters = types;
+      mRealInnerClasses = realInnerClasses;
+    }
+
+    public ClassInfo[] getRealInnerClasses(){
+      return mRealInnerClasses;
+    }
+
+    public TypeInfo[] getTypeParameters(){
+      return mTypeParameters;
+    }
+
+    public boolean checkLevel()
+    {
+        int val = mCheckLevel;
+        if (val >= 0) {
+            return val != 0;
+        } else {
+            boolean v = DroidDoc.checkLevel(mIsPublic, mIsProtected,
+                                                mIsPackagePrivate, mIsPrivate, isHidden());
+            mCheckLevel = v ? 1 : 0;
+            return v;
+        }
+    }
+
+    public int compareTo(Object that) {
+        if (that instanceof ClassInfo) {
+            return mQualifiedName.compareTo(((ClassInfo)that).mQualifiedName);
+        } else {
+            return this.hashCode() - that.hashCode();
+        }
+    }
+
+    @Override
+    public ContainerInfo parent()
+    {
+        return this;
+    }
+
+    public boolean isPublic()
+    {
+        return mIsPublic;
+    }
+
+    public boolean isProtected()
+    {
+        return mIsProtected;
+    }
+
+    public boolean isPackagePrivate()
+    {
+        return mIsPackagePrivate;
+    }
+
+    public boolean isPrivate()
+    {
+        return mIsPrivate;
+    }
+
+    public boolean isStatic()
+    {
+        return mIsStatic;
+    }
+
+    public boolean isInterface()
+    {
+        return mIsInterface;
+    }
+
+    public boolean isAbstract()
+    {
+        return mIsAbstract;
+    }
+
+    public PackageInfo containingPackage()
+    {
+        return mContainingPackage;
+    }
+
+    public ClassInfo containingClass()
+    {
+        return mContainingClass;
+    }
+
+    public boolean isOrdinaryClass()
+    {
+        return mIsOrdinaryClass;
+    }
+
+    public boolean isException()
+    {
+        return mIsException;
+    }
+
+    public boolean isError()
+    {
+        return mIsError;
+    }
+
+    public boolean isEnum()
+    {
+        return mIsEnum;
+    }
+
+    public boolean isAnnotation()
+    {
+        return mIsAnnotation;
+    }
+
+    public boolean isFinal()
+    {
+        return mIsFinal;
+    }
+
+    public boolean isIncluded()
+    {
+        return mIsIncluded;
+    }
+
+    public HashSet<String> typeVariables()
+    {
+        HashSet<String> result = TypeInfo.typeVariables(mTypeInfo.typeArguments());
+        ClassInfo cl = containingClass();
+        while (cl != null) {
+            TypeInfo[] types = cl.asTypeInfo().typeArguments();
+            if (types != null) {
+                TypeInfo.typeVariables(types, result);
+            }
+            cl = cl.containingClass();
+        }
+        return result;
+    }
+
+    private static void gatherHiddenInterfaces(ClassInfo cl, HashSet<ClassInfo> interfaces) {
+        for (ClassInfo iface: cl.mRealInterfaces) {
+            if (iface.checkLevel()) {
+                interfaces.add(iface);
+            } else {
+                gatherHiddenInterfaces(iface, interfaces);
+            }
+        }
+    }
+
+    public ClassInfo[] interfaces()
+    {
+        if (mInterfaces == null) {
+            if (checkLevel()) {
+                HashSet<ClassInfo> interfaces = new HashSet<ClassInfo>();
+                ClassInfo superclass = mRealSuperclass;
+                while (superclass != null && !superclass.checkLevel()) {
+                    gatherHiddenInterfaces(superclass, interfaces);
+                    superclass = superclass.mRealSuperclass;
+                }
+                gatherHiddenInterfaces(this, interfaces);
+                mInterfaces = interfaces.toArray(new ClassInfo[interfaces.size()]);
+            } else {
+                // put something here in case someone uses it
+                mInterfaces = mRealInterfaces;
+            }
+            Arrays.sort(mInterfaces, ClassInfo.qualifiedComparator);
+        }
+        return mInterfaces;
+    }
+
+    public ClassInfo[] realInterfaces()
+    {
+        return mRealInterfaces;
+    }
+
+    TypeInfo[] realInterfaceTypes()
+    {
+        return mRealInterfaceTypes;
+    }
+
+    public String name()
+    {
+        return mName;
+    }
+
+    public String[] nameParts()
+    {
+        return mNameParts;
+    }
+
+    public String leafName()
+    {
+        return mNameParts[mNameParts.length-1];
+    }
+
+    public String qualifiedName()
+    {
+        return mQualifiedName;
+    }
+
+    public String qualifiedTypeName()
+    {
+        return mQualifiedTypeName;
+    }
+
+    public boolean isPrimitive()
+    {
+        return mIsPrimitive;
+    }
+
+    public MethodInfo[] allConstructors() {
+        return mAllConstructors;
+    }
+
+    public MethodInfo[] constructors()
+    {
+        if (mConstructors == null) {
+            MethodInfo[] methods = mAllConstructors;
+            ArrayList<MethodInfo> ctors = new ArrayList<MethodInfo>();
+            for (int i=0; i<methods.length; i++) {
+                MethodInfo m = methods[i];
+                if (!m.isHidden()) {
+                    ctors.add(m);
+                }
+            }
+            mConstructors = ctors.toArray(new MethodInfo[ctors.size()]);
+            Arrays.sort(mConstructors, MethodInfo.comparator);
+        }
+        return mConstructors;
+    }
+
+    public ClassInfo[] innerClasses()
+    {
+        return mInnerClasses;
+    }
+
+    public TagInfo[] inlineTags()
+    {
+        return comment().tags();
+    }
+
+    public TagInfo[] firstSentenceTags()
+    {
+        return comment().briefTags();
+    }
+
+    public boolean isDeprecated() {
+        boolean deprecated = false;
+        if (!mDeprecatedKnown) {
+            boolean commentDeprecated = (comment().deprecatedTags().length > 0);
+            boolean annotationDeprecated = false;
+            for (AnnotationInstanceInfo annotation : annotations()) {
+                if (annotation.type().qualifiedName().equals("java.lang.Deprecated")) {
+                    annotationDeprecated = true;
+                    break;
+                }
+            }
+
+            if (commentDeprecated != annotationDeprecated) {
+                Errors.error(Errors.DEPRECATION_MISMATCH, position(),
+                        "Class " + qualifiedName()
+                        + ": @Deprecated annotation and @deprecated comment do not match");
+            }
+
+            mIsDeprecated = commentDeprecated | annotationDeprecated;
+            mDeprecatedKnown = true;
+        }
+        return mIsDeprecated;
+    }
+
+    public TagInfo[] deprecatedTags()
+    {
+        // Should we also do the interfaces?
+        return comment().deprecatedTags();
+    }
+
+    public MethodInfo[] methods()
+    {
+        if (mMethods == null) {
+            TreeMap<String,MethodInfo> all = new TreeMap<String,MethodInfo>();
+
+            ClassInfo[] ifaces = interfaces();
+            for (ClassInfo iface: ifaces) {
+                if (iface != null) {
+                    MethodInfo[] inhereted = iface.methods();
+                    for (MethodInfo method: inhereted) {
+                        String key = method.name() + method.signature();
+                        all.put(key, method);
+                    }
+                }
+            }
+
+            ClassInfo superclass = superclass();
+            if (superclass != null) {
+                MethodInfo[] inhereted = superclass.methods();
+                for (MethodInfo method: inhereted) {
+                    String key = method.name() + method.signature();
+                    all.put(key, method);
+                }
+            }
+
+            MethodInfo[] methods = selfMethods();
+            for (MethodInfo method: methods) {
+                String key = method.name() + method.signature();
+                MethodInfo old = all.put(key, method);
+            }
+
+            mMethods = all.values().toArray(new MethodInfo[all.size()]);
+        }
+        return mMethods;
+    }
+
+    public MethodInfo[] annotationElements()
+    {
+        return mAnnotationElements;
+    }
+
+    public AnnotationInstanceInfo[] annotations()
+    {
+        return mAnnotations;
+    }
+
+    private static void addFields(ClassInfo cl, TreeMap<String,FieldInfo> all)
+    {
+        FieldInfo[] fields = cl.fields();
+        int N = fields.length;
+        for (int i=0; i<N; i++) {
+            FieldInfo f = fields[i];
+            all.put(f.name(), f);
+        }
+    }
+
+    public FieldInfo[] fields()
+    {
+        if (mFields == null) {
+            int N;
+            TreeMap<String,FieldInfo> all = new TreeMap<String,FieldInfo>();
+
+            ClassInfo[] interfaces = interfaces();
+            N = interfaces.length;
+            for (int i=0; i<N; i++) {
+                addFields(interfaces[i], all);
+            }
+
+            ClassInfo superclass = superclass();
+            if (superclass != null) {
+                addFields(superclass, all);
+            }
+
+            FieldInfo[] fields = selfFields();
+            N = fields.length;
+            for (int i=0; i<N; i++) {
+                FieldInfo f = fields[i];
+                if (!f.isHidden()) {
+                    String key = f.name();
+                    all.put(key, f);
+                }
+            }
+
+            mFields = all.values().toArray(new FieldInfo[0]);
+        }
+        return mFields;
+    }
+
+    public void gatherFields(ClassInfo owner, ClassInfo cl, HashMap<String,FieldInfo> fields) {
+        FieldInfo[] flds = cl.selfFields();
+        for (FieldInfo f: flds) {
+            if (f.checkLevel()) {
+                fields.put(f.name(), f.cloneForClass(owner));
+            }
+        }
+    }
+
+    public FieldInfo[] selfFields()
+    {
+        if (mSelfFields == null) {
+            HashMap<String,FieldInfo> fields = new HashMap<String,FieldInfo>();
+            // our hidden parents
+            if (mRealSuperclass != null && !mRealSuperclass.checkLevel()) {
+                gatherFields(this, mRealSuperclass, fields);
+            }
+            for (ClassInfo iface: mRealInterfaces) {
+                if (!iface.checkLevel()) {
+                    gatherFields(this, iface, fields);
+                }
+            }
+            // mine
+            FieldInfo[] selfFields = mAllSelfFields;
+            for (int i=0; i<selfFields.length; i++) {
+                FieldInfo f = selfFields[i];
+                if (!f.isHidden()) {
+                    fields.put(f.name(), f);
+                }
+            }
+            // combine and return in
+            mSelfFields = fields.values().toArray(new FieldInfo[fields.size()]);
+            Arrays.sort(mSelfFields, FieldInfo.comparator);
+        }
+        return mSelfFields;
+    }
+
+    public FieldInfo[] allSelfFields() {
+        return mAllSelfFields;
+    }
+
+    public void gatherMethods(ClassInfo owner, ClassInfo cl, HashMap<String,MethodInfo> methods) {
+        MethodInfo[] meth = cl.selfMethods();
+        for (MethodInfo m: meth) {
+            if (m.checkLevel()) {
+                methods.put(m.name()+m.signature(), m.cloneForClass(owner));
+            }
+        }
+    }
+
+    public MethodInfo[] selfMethods()
+    {
+        if (mSelfMethods == null) {
+            HashMap<String,MethodInfo> methods = new HashMap<String,MethodInfo>();
+            // our hidden parents
+            if (mRealSuperclass != null && !mRealSuperclass.checkLevel()) {
+                gatherMethods(this, mRealSuperclass, methods);
+            }
+            for (ClassInfo iface: mRealInterfaces) {
+                if (!iface.checkLevel()) {
+                    gatherMethods(this, iface, methods);
+                }
+            }
+            // mine
+            MethodInfo[] selfMethods = mAllSelfMethods;
+            for (int i=0; i<selfMethods.length; i++) {
+                MethodInfo m = selfMethods[i];
+                if (m.checkLevel()) {
+                    methods.put(m.name()+m.signature(), m);
+                }
+            }
+            // combine and return it
+            mSelfMethods = methods.values().toArray(new MethodInfo[methods.size()]);
+            Arrays.sort(mSelfMethods, MethodInfo.comparator);
+        }
+        return mSelfMethods;
+    }
+
+    public MethodInfo[] allSelfMethods() {
+        return mAllSelfMethods;
+    }
+
+    public void addMethod(MethodInfo method) {
+        MethodInfo[] methods = new MethodInfo[mAllSelfMethods.length + 1];
+        int i = 0;
+        for (MethodInfo m : mAllSelfMethods) {
+            methods[i] = m;
+            i++;
+        }
+        methods[i] = method;
+        mAllSelfMethods = methods;
+    }
+
+    public AttributeInfo[] selfAttributes()
+    {
+        if (mSelfAttributes == null) {
+            TreeMap<FieldInfo,AttributeInfo> attrs = new TreeMap<FieldInfo,AttributeInfo>();
+
+            // the ones in the class comment won't have any methods
+            for (AttrTagInfo tag: comment().attrTags()) {
+                FieldInfo field = tag.reference();
+                if (field != null) {
+                    AttributeInfo attr = attrs.get(field);
+                    if (attr == null) {
+                        attr = new AttributeInfo(this, field);
+                        attrs.put(field, attr);
+                    }
+                    tag.setAttribute(attr);
+                }
+            }
+
+            // in the methods
+            for (MethodInfo m: selfMethods()) {
+                for (AttrTagInfo tag: m.comment().attrTags()) {
+                    FieldInfo field = tag.reference();
+                    if (field != null) {
+                        AttributeInfo attr = attrs.get(field);
+                        if (attr == null) {
+                            attr = new AttributeInfo(this, field);
+                            attrs.put(field, attr);
+                        }
+                        tag.setAttribute(attr);
+                        attr.methods.add(m);
+                    }
+                }
+            }
+
+            //constructors too
+           for (MethodInfo m: constructors()) {
+              for (AttrTagInfo tag: m.comment().attrTags()) {
+                  FieldInfo field = tag.reference();
+                  if (field != null) {
+                      AttributeInfo attr = attrs.get(field);
+                      if (attr == null) {
+                          attr = new AttributeInfo(this, field);
+                          attrs.put(field, attr);
+                      }
+                      tag.setAttribute(attr);
+                      attr.methods.add(m);
+                  }
+              }
+          }
+
+            mSelfAttributes = attrs.values().toArray(new AttributeInfo[attrs.size()]);
+            Arrays.sort(mSelfAttributes, AttributeInfo.comparator);
+        }
+        return mSelfAttributes;
+    }
+
+    public FieldInfo[] enumConstants()
+    {
+        return mEnumConstants;
+    }
+
+    public ClassInfo superclass()
+    {
+        if (!mSuperclassInit) {
+            if (this.checkLevel()) {
+                // rearrange our little inheritance hierarchy, because we need to hide classes that
+                // don't pass checkLevel
+                ClassInfo superclass = mRealSuperclass;
+                while (superclass != null && !superclass.checkLevel()) {
+                    superclass = superclass.mRealSuperclass;
+                }
+                mSuperclass = superclass;
+            } else {
+                mSuperclass = mRealSuperclass;
+            }
+        }
+        return mSuperclass;
+    }
+
+    public ClassInfo realSuperclass()
+    {
+        return mRealSuperclass;
+    }
+
+    /** always the real superclass, not the collapsed one we get through superclass(),
+     * also has the type parameter info if it's generic.
+     */
+    public TypeInfo superclassType()
+    {
+        return mRealSuperclassType;
+    }
+
+    public TypeInfo asTypeInfo()
+    {
+        return mTypeInfo;
+    }
+
+    TypeInfo[] interfaceTypes()
+    {
+        ClassInfo[] infos = interfaces();
+        int len = infos.length;
+        TypeInfo[] types = new TypeInfo[len];
+        for (int i=0; i<len; i++) {
+            types[i] = infos[i].asTypeInfo();
+        }
+        return types;
+    }
+
+    public String htmlPage()
+    {
+        String s = containingPackage().name();
+        s = s.replace('.', '/');
+        s += '/';
+        s += name();
+        s += ".html";
+        s = DroidDoc.javadocDir + s;
+        return s;
+    }
+
+    /** Even indirectly */
+    public boolean isDerivedFrom(ClassInfo cl)
+    {
+        ClassInfo dad = this.superclass();
+        if (dad != null) {
+            if (dad.equals(cl)) {
+                return true;
+            } else {
+                if (dad.isDerivedFrom(cl)) {
+                    return true;
+                }
+            }
+        }
+        for (ClassInfo iface: interfaces()) {
+            if (iface.equals(cl)) {
+                return true;
+            } else {
+                if (iface.isDerivedFrom(cl)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public void makeKeywordEntries(List<KeywordEntry> keywords)
+    {
+        if (!checkLevel()) {
+            return;
+        }
+
+        String htmlPage = htmlPage();
+        String qualifiedName = qualifiedName();
+
+        keywords.add(new KeywordEntry(name(), htmlPage,
+                "class in " + containingPackage().name()));
+
+        FieldInfo[] fields = selfFields();
+        FieldInfo[] enumConstants = enumConstants();
+        MethodInfo[] ctors = constructors();
+        MethodInfo[] methods = selfMethods();
+
+        // enum constants
+        for (FieldInfo field: enumConstants()) {
+            if (field.checkLevel()) {
+                keywords.add(new KeywordEntry(field.name(),
+                            htmlPage + "#" + field.anchor(),
+                            "enum constant in " + qualifiedName));
+            }
+        }
+
+        // constants
+        for (FieldInfo field: fields) {
+            if (field.isConstant() && field.checkLevel()) {
+                keywords.add(new KeywordEntry(field.name(),
+                            htmlPage + "#" + field.anchor(),
+                            "constant in " + qualifiedName));
+            }
+        }
+
+        // fields
+        for (FieldInfo field: fields) {
+            if (!field.isConstant() && field.checkLevel()) {
+                keywords.add(new KeywordEntry(field.name(),
+                            htmlPage + "#" + field.anchor(),
+                            "field in " + qualifiedName));
+            }
+        }
+
+        // public constructors
+        for (MethodInfo m: ctors) {
+            if (m.isPublic() && m.checkLevel()) {
+                keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
+                            htmlPage + "#" + m.anchor(),
+                            "constructor in " + qualifiedName));
+            }
+        }
+
+        // protected constructors
+        if (DroidDoc.checkLevel(DroidDoc.SHOW_PROTECTED)) {
+            for (MethodInfo m: ctors) {
+                if (m.isProtected() && m.checkLevel()) {
+                    keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
+                                htmlPage + "#" + m.anchor(),
+                                "constructor in " + qualifiedName));
+                }
+            }
+        }
+
+        // package private constructors
+        if (DroidDoc.checkLevel(DroidDoc.SHOW_PACKAGE)) {
+            for (MethodInfo m: ctors) {
+                if (m.isPackagePrivate() && m.checkLevel()) {
+                    keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
+                                htmlPage + "#" + m.anchor(),
+                                "constructor in " + qualifiedName));
+                }
+            }
+        }
+
+        // private constructors
+        if (DroidDoc.checkLevel(DroidDoc.SHOW_PRIVATE)) {
+            for (MethodInfo m: ctors) {
+                if (m.isPrivate() && m.checkLevel()) {
+                    keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
+                                htmlPage + "#" + m.anchor(),
+                                "constructor in " + qualifiedName));
+                }
+            }
+        }
+
+        // public methods
+        for (MethodInfo m: methods) {
+            if (m.isPublic() && m.checkLevel()) {
+                keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
+                            htmlPage + "#" + m.anchor(),
+                            "method in " + qualifiedName));
+            }
+        }
+
+        // protected methods
+        if (DroidDoc.checkLevel(DroidDoc.SHOW_PROTECTED)) {
+            for (MethodInfo m: methods) {
+                if (m.isProtected() && m.checkLevel()) {
+                    keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
+                                htmlPage + "#" + m.anchor(),
+                                "method in " + qualifiedName));
+                }
+            }
+        }
+
+        // package private methods
+        if (DroidDoc.checkLevel(DroidDoc.SHOW_PACKAGE)) {
+            for (MethodInfo m: methods) {
+                if (m.isPackagePrivate() && m.checkLevel()) {
+                    keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
+                                htmlPage + "#" + m.anchor(),
+                                "method in " + qualifiedName));
+                }
+            }
+        }
+
+        // private methods
+        if (DroidDoc.checkLevel(DroidDoc.SHOW_PRIVATE)) {
+            for (MethodInfo m: methods) {
+                if (m.isPrivate() && m.checkLevel()) {
+                    keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
+                                htmlPage + "#" + m.anchor(),
+                                "method in " + qualifiedName));
+                }
+            }
+        }
+    }
+
+    public void makeLink(HDF data, String base)
+    {
+        data.setValue(base + ".label", this.name());
+        if (!this.isPrimitive() && this.isIncluded() && this.checkLevel()) {
+            data.setValue(base + ".link", this.htmlPage());
+        }
+    }
+
+    public static void makeLinkListHDF(HDF data, String base, ClassInfo[] classes) {
+        final int N = classes.length;
+        for (int i=0; i<N; i++) {
+            ClassInfo cl = classes[i];
+            if (cl.checkLevel()) {
+                cl.asTypeInfo().makeHDF(data, base + "." + i);
+            }
+        }
+    }
+
+    /**
+     * Used in lists of this class (packages, nested classes, known subclasses)
+     */
+    public void makeShortDescrHDF(HDF data, String base)
+    {
+        mTypeInfo.makeHDF(data, base + ".type");
+        data.setValue(base + ".kind", this.kind());
+        TagInfo.makeHDF(data, base + ".shortDescr", this.firstSentenceTags());
+        TagInfo.makeHDF(data, base + ".deprecated", deprecatedTags());
+        data.setValue(base + ".since", getSince());
+    }
+
+    /**
+     * Turns into the main class page
+     */
+    public void makeHDF(HDF data)
+    {
+        int i, j, n;
+        String name = name();
+        String qualified = qualifiedName();
+        AttributeInfo[] selfAttributes = selfAttributes();
+        MethodInfo[] methods = selfMethods();
+        FieldInfo[] fields = selfFields();
+        FieldInfo[] enumConstants = enumConstants();
+        MethodInfo[] ctors = constructors();
+        ClassInfo[] inners = innerClasses();
+
+        // class name
+        mTypeInfo.makeHDF(data, "class.type");
+        mTypeInfo.makeQualifiedHDF(data, "class.qualifiedType");
+        data.setValue("class.name", name);
+        data.setValue("class.qualified", qualified);
+        String scope = "";
+        if (isProtected()) {
+            data.setValue("class.scope", "protected");
+        }
+        else if (isPublic()) {
+            data.setValue("class.scope", "public");
+        }
+        if (isStatic()) {
+            data.setValue("class.static", "static");
+        }
+        if (isFinal()) {
+            data.setValue("class.final", "final");
+        }
+        if (isAbstract() && !isInterface()) {
+            data.setValue("class.abstract", "abstract");
+        }
+
+        // class info
+        String kind = kind();
+        if (kind != null) {
+            data.setValue("class.kind", kind);
+        }
+        data.setValue("class.since", getSince());
+
+        // the containing package -- note that this can be passed to type_link,
+        // but it also contains the list of all of the packages
+        containingPackage().makeClassLinkListHDF(data, "class.package");
+
+        // inheritance hierarchy
+        Vector<ClassInfo> superClasses = new Vector<ClassInfo>();
+        superClasses.add(this);
+        ClassInfo supr = superclass();
+        while (supr != null) {
+            superClasses.add(supr);
+            supr = supr.superclass();
+        }
+        n = superClasses.size();
+        for (i=0; i<n; i++) {
+            supr = superClasses.elementAt(n-i-1);
+
+            supr.asTypeInfo().makeQualifiedHDF(data, "class.inheritance." + i + ".class");
+            supr.asTypeInfo().makeHDF(data, "class.inheritance." + i + ".short_class");
+            j = 0;
+            for (TypeInfo t: supr.interfaceTypes()) {
+                t.makeHDF(data, "class.inheritance." + i + ".interfaces." + j);
+                j++;
+            }
+        }
+
+        // class description
+        TagInfo.makeHDF(data, "class.descr", inlineTags());
+        TagInfo.makeHDF(data, "class.seeAlso", comment().seeTags());
+        TagInfo.makeHDF(data, "class.deprecated", deprecatedTags());
+
+        // known subclasses
+        TreeMap<String, ClassInfo> direct = new TreeMap<String, ClassInfo>();
+        TreeMap<String, ClassInfo> indirect = new TreeMap<String, ClassInfo>();
+        ClassInfo[] all = Converter.rootClasses();
+        for (ClassInfo cl: all) {
+            if (cl.superclass() != null && cl.superclass().equals(this)) {
+                direct.put(cl.name(), cl);
+            }
+            else if (cl.isDerivedFrom(this)) {
+                indirect.put(cl.name(), cl);
+            }
+        }
+        // direct
+        i = 0;
+        for (ClassInfo cl: direct.values()) {
+            if (cl.checkLevel()) {
+                cl.makeShortDescrHDF(data, "class.subclasses.direct." + i);
+            }
+            i++;
+        }
+        // indirect
+        i = 0;
+        for (ClassInfo cl: indirect.values()) {
+            if (cl.checkLevel()) {
+                cl.makeShortDescrHDF(data, "class.subclasses.indirect." + i);
+            }
+            i++;
+        }
+
+        // nested classes
+        i=0;
+        for (ClassInfo inner: inners) {
+            if (inner.checkLevel()) {
+                inner.makeShortDescrHDF(data, "class.inners." + i);
+            }
+            i++;
+        }
+
+        // enum constants
+        i=0;
+        for (FieldInfo field: enumConstants) {
+            if (field.isConstant()) {
+                field.makeHDF(data, "class.enumConstants." + i);
+                i++;
+            }
+        }
+
+        // constants
+        i=0;
+        for (FieldInfo field: fields) {
+            if (field.isConstant()) {
+                field.makeHDF(data, "class.constants." + i);
+                i++;
+            }
+        }
+
+        // fields
+        i=0;
+        for (FieldInfo field: fields) {
+            if (!field.isConstant()) {
+                field.makeHDF(data, "class.fields." + i);
+                i++;
+            }
+        }
+
+        // public constructors
+        i=0;
+        for (MethodInfo ctor: ctors) {
+            if (ctor.isPublic()) {
+                ctor.makeHDF(data, "class.ctors.public." + i);
+                i++;
+            }
+        }
+
+        // protected constructors
+        if (DroidDoc.checkLevel(DroidDoc.SHOW_PROTECTED)) {
+            i=0;
+            for (MethodInfo ctor: ctors) {
+                if (ctor.isProtected()) {
+                    ctor.makeHDF(data, "class.ctors.protected." + i);
+                    i++;
+                }
+            }
+        }
+
+        // package private constructors
+        if (DroidDoc.checkLevel(DroidDoc.SHOW_PACKAGE)) {
+            i=0;
+            for (MethodInfo ctor: ctors) {
+                if (ctor.isPackagePrivate()) {
+                    ctor.makeHDF(data, "class.ctors.package." + i);
+                    i++;
+                }
+            }
+        }
+
+        // private constructors
+        if (DroidDoc.checkLevel(DroidDoc.SHOW_PRIVATE)) {
+            i=0;
+            for (MethodInfo ctor: ctors) {
+                if (ctor.isPrivate()) {
+                    ctor.makeHDF(data, "class.ctors.private." + i);
+                    i++;
+                }
+            }
+        }
+
+        // public methods
+        i=0;
+        for (MethodInfo method: methods) {
+            if (method.isPublic()) {
+                method.makeHDF(data, "class.methods.public." + i);
+                i++;
+            }
+        }
+
+        // protected methods
+        if (DroidDoc.checkLevel(DroidDoc.SHOW_PROTECTED)) {
+            i=0;
+            for (MethodInfo method: methods) {
+                if (method.isProtected()) {
+                    method.makeHDF(data, "class.methods.protected." + i);
+                    i++;
+                }
+            }
+        }
+
+        // package private methods
+        if (DroidDoc.checkLevel(DroidDoc.SHOW_PACKAGE)) {
+            i=0;
+            for (MethodInfo method: methods) {
+                if (method.isPackagePrivate()) {
+                    method.makeHDF(data, "class.methods.package." + i);
+                    i++;
+                }
+            }
+        }
+
+        // private methods
+        if (DroidDoc.checkLevel(DroidDoc.SHOW_PRIVATE)) {
+            i=0;
+            for (MethodInfo method: methods) {
+                if (method.isPrivate()) {
+                    method.makeHDF(data, "class.methods.private." + i);
+                    i++;
+                }
+            }
+        }
+
+        // xml attributes
+        i=0;
+        for (AttributeInfo attr: selfAttributes) {
+            if (attr.checkLevel()) {
+                attr.makeHDF(data, "class.attrs." + i);
+                i++;
+            }
+        }
+
+        // inherited methods
+        Set<ClassInfo> interfaces = new TreeSet<ClassInfo>();
+        addInterfaces(interfaces(), interfaces);
+        ClassInfo cl = superclass();
+        i=0;
+        while (cl != null) {
+            addInterfaces(cl.interfaces(), interfaces);
+            makeInheritedHDF(data, i, cl);
+            cl = cl.superclass();
+            i++;
+        }
+        for (ClassInfo iface: interfaces) {
+            makeInheritedHDF(data, i, iface);
+            i++;
+        }
+    }
+
+    private static void addInterfaces(ClassInfo[] ifaces, Set<ClassInfo> out)
+    {
+        for (ClassInfo cl: ifaces) {
+            out.add(cl);
+            addInterfaces(cl.interfaces(), out);
+        }
+    }
+
+    private static void makeInheritedHDF(HDF data, int index, ClassInfo cl)
+    {
+        int i;
+
+        String base = "class.inherited." + index;
+        data.setValue(base + ".qualified", cl.qualifiedName());
+        if (cl.checkLevel()) {
+            data.setValue(base + ".link", cl.htmlPage());
+        }
+        String kind = cl.kind();
+        if (kind != null) {
+            data.setValue(base + ".kind", kind);
+        }
+
+        if (cl.mIsIncluded) {
+            data.setValue(base + ".included", "true");
+        }
+
+        // xml attributes
+        i=0;
+        for (AttributeInfo attr: cl.selfAttributes()) {
+            attr.makeHDF(data, base + ".attrs." + i);
+            i++;
+        }
+
+        // methods
+        i=0;
+        for (MethodInfo method: cl.selfMethods()) {
+            method.makeHDF(data, base + ".methods." + i);
+            i++;
+        }
+
+        // fields
+        i=0;
+        for (FieldInfo field: cl.selfFields()) {
+            if (!field.isConstant()) {
+                field.makeHDF(data, base + ".fields." + i);
+                i++;
+            }
+        }
+
+        // constants
+        i=0;
+        for (FieldInfo field: cl.selfFields()) {
+            if (field.isConstant()) {
+                field.makeHDF(data, base + ".constants." + i);
+                i++;
+            }
+        }
+    }
+
+    @Override
+    public boolean isHidden()
+    {
+        int val = mHidden;
+        if (val >= 0) {
+            return val != 0;
+        } else {
+            boolean v = isHiddenImpl();
+            mHidden = v ? 1 : 0;
+            return v;
+        }
+    }
+
+    public boolean isHiddenImpl()
+    {
+        ClassInfo cl = this;
+        while (cl != null) {
+            PackageInfo pkg = cl.containingPackage();
+            if (pkg != null && pkg.isHidden()) {
+                return true;
+            }
+            if (cl.comment().isHidden()) {
+                return true;
+            }
+            cl = cl.containingClass();
+        }
+        return false;
+    }
+
+    private MethodInfo matchMethod(MethodInfo[] methods, String name,
+                                    String[] params, String[] dimensions)
+    {
+        int len = methods.length;
+        for (int i=0; i<len; i++) {
+            MethodInfo method = methods[i];
+            if (method.name().equals(name)) {
+                if (params == null) {
+                    return method;
+                } else {
+                    if (method.matchesParams(params, dimensions)) {
+                        return method;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    public MethodInfo findMethod(String name,
+                                    String[] params, String[] dimensions)
+    {
+        // first look on our class, and our superclasses
+
+        // for methods
+        MethodInfo rv;
+        rv = matchMethod(methods(), name, params, dimensions);
+
+        if (rv != null) {
+            return rv;
+        }
+
+        // for constructors
+        rv = matchMethod(constructors(), name, params, dimensions);
+        if (rv != null) {
+            return rv;
+        }
+
+        // then recursively look at our containing class
+        ClassInfo containing = containingClass();
+        if (containing != null) {
+            return containing.findMethod(name, params, dimensions);
+        }
+
+        return null;
+    }
+
+    private ClassInfo searchInnerClasses(String[] nameParts, int index)
+    {
+        String part = nameParts[index];
+
+        ClassInfo[] inners = mInnerClasses;
+        for (ClassInfo in: inners) {
+            String[] innerParts = in.nameParts();
+            if (part.equals(innerParts[innerParts.length-1])) {
+                if (index == nameParts.length-1) {
+                    return in;
+                } else {
+                    return in.searchInnerClasses(nameParts, index+1);
+                }
+            }
+        }
+        return null;
+    }
+
+    public ClassInfo extendedFindClass(String className)
+    {
+        // ClassDoc.findClass has this bug that we're working around here:
+        // If you have a class PackageManager with an inner class PackageInfo
+        // and you call it with "PackageInfo" it doesn't find it.
+        return searchInnerClasses(className.split("\\."), 0);
+    }
+
+    public ClassInfo findClass(String className)
+    {
+        return Converter.obtainClass(mClass.findClass(className));
+    }
+
+    public ClassInfo findInnerClass(String className)
+    {
+        // ClassDoc.findClass won't find inner classes.  To deal with that,
+        // we try what they gave us first, but if that didn't work, then
+        // we see if there are any periods in className, and start searching
+        // from there.
+        String[] nodes = className.split("\\.");
+        ClassDoc cl = mClass;
+        for (String n: nodes) {
+            cl = cl.findClass(n);
+            if (cl == null) {
+                return null;
+            }
+        }
+        return Converter.obtainClass(cl);
+    }
+
+    public FieldInfo findField(String name)
+    {
+        // first look on our class, and our superclasses
+        for (FieldInfo f: fields()) {
+            if (f.name().equals(name)) {
+                return f;
+            }
+        }
+
+        // then look at our enum constants (these are really fields, maybe
+        // they should be mixed into fields().  not sure)
+        for (FieldInfo f: enumConstants()) {
+            if (f.name().equals(name)) {
+                return f;
+            }
+        }
+
+        // then recursively look at our containing class
+        ClassInfo containing = containingClass();
+        if (containing != null) {
+            return containing.findField(name);
+        }
+
+        return null;
+    }
+
+    public static ClassInfo[] sortByName(ClassInfo[] classes)
+    {
+        int i;
+        Sorter[] sorted = new Sorter[classes.length];
+        for (i=0; i<sorted.length; i++) {
+            ClassInfo cl = classes[i];
+            sorted[i] = new Sorter(cl.name(), cl);
+        }
+
+        Arrays.sort(sorted);
+
+        ClassInfo[] rv = new ClassInfo[classes.length];
+        for (i=0; i<rv.length; i++) {
+            rv[i] = (ClassInfo)sorted[i].data;
+        }
+
+        return rv;
+    }
+
+    public boolean equals(ClassInfo that)
+    {
+        if (that != null) {
+            return this.qualifiedName().equals(that.qualifiedName());
+        } else {
+            return false;
+        }
+    }
+
+    public void setNonWrittenConstructors(MethodInfo[] nonWritten) {
+        mNonWrittenConstructors = nonWritten;
+    }
+
+    public MethodInfo[] getNonWrittenConstructors() {
+        return mNonWrittenConstructors;
+    }
+
+    public String kind()
+    {
+        if (isOrdinaryClass()) {
+            return "class";
+        }
+        else if (isInterface()) {
+            return "interface";
+        }
+        else if (isEnum()) {
+            return "enum";
+        }
+        else if (isError()) {
+            return "class";
+        }
+        else if (isException()) {
+            return "class";
+        }
+        else if (isAnnotation()) {
+            return "@interface";
+        }
+        return null;
+    }
+
+    public void setHiddenMethods(MethodInfo[] mInfo){
+        mHiddenMethods = mInfo;
+    }
+    public MethodInfo[] getHiddenMethods(){
+        return mHiddenMethods;
+    }
+    @Override
+    public String toString(){
+        return this.qualifiedName();
+    }
+
+    public void setReasonIncluded(String reason) {
+        mReasonIncluded = reason;
+    }
+
+    public String getReasonIncluded() {
+        return mReasonIncluded;
+    }
+
+    private ClassDoc mClass;
+
+    // ctor
+    private boolean mIsPublic;
+    private boolean mIsProtected;
+    private boolean mIsPackagePrivate;
+    private boolean mIsPrivate;
+    private boolean mIsStatic;
+    private boolean mIsInterface;
+    private boolean mIsAbstract;
+    private boolean mIsOrdinaryClass;
+    private boolean mIsException;
+    private boolean mIsError;
+    private boolean mIsEnum;
+    private boolean mIsAnnotation;
+    private boolean mIsFinal;
+    private boolean mIsIncluded;
+    private String mName;
+    private String mQualifiedName;
+    private String mQualifiedTypeName;
+    private boolean mIsPrimitive;
+    private TypeInfo mTypeInfo;
+    private String[] mNameParts;
+
+    // init
+    private ClassInfo[] mRealInterfaces;
+    private ClassInfo[] mInterfaces;
+    private TypeInfo[] mRealInterfaceTypes;
+    private ClassInfo[] mInnerClasses;
+    private MethodInfo[] mAllConstructors;
+    private MethodInfo[] mAllSelfMethods;
+    private MethodInfo[] mAnnotationElements; // if this class is an annotation
+    private FieldInfo[] mAllSelfFields;
+    private FieldInfo[] mEnumConstants;
+    private PackageInfo mContainingPackage;
+    private ClassInfo mContainingClass;
+    private ClassInfo mRealSuperclass;
+    private TypeInfo mRealSuperclassType;
+    private ClassInfo mSuperclass;
+    private AnnotationInstanceInfo[] mAnnotations;
+    private boolean mSuperclassInit;
+    private boolean mDeprecatedKnown;
+
+    // lazy
+    private MethodInfo[] mConstructors;
+    private ClassInfo[] mRealInnerClasses;
+    private MethodInfo[] mSelfMethods;
+    private FieldInfo[] mSelfFields;
+    private AttributeInfo[] mSelfAttributes;
+    private MethodInfo[] mMethods;
+    private FieldInfo[] mFields;
+    private TypeInfo[] mTypeParameters;
+    private MethodInfo[] mHiddenMethods;
+    private int mHidden = -1;
+    private int mCheckLevel = -1;
+    private String mReasonIncluded;
+    private MethodInfo[] mNonWrittenConstructors;
+    private boolean mIsDeprecated;
+}
diff --git a/build/tools/droiddoc/src/ClearPage.java b/build/tools/droiddoc/src/ClearPage.java
new file mode 100644 (file)
index 0000000..016ca93
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.sun.javadoc.*;
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ClearPage
+{
+    /*
+    public ClearPage()
+    {
+        String templ = "templates/index.cs";
+        String filename = "docs/index.html";
+
+        data.setValue("A.B.C", "1");
+        data.setValue("A.B.D", "2");
+    }
+    */
+
+    public static ArrayList<String> hdfFiles = new ArrayList<String>();
+
+    private static ArrayList<String> mTemplateDirs = new ArrayList<String>();
+    private static boolean mTemplateDirSet = false;
+
+    public static String outputDir = "docs";
+    public static List<String> htmlDirs = new ArrayList<String>();
+    public static String toroot = null;
+
+    public static void addTemplateDir(String dir)
+    {
+        mTemplateDirSet = true;
+        mTemplateDirs.add(dir);
+
+        File hdfFile = new File(dir, "data.hdf");
+        if (hdfFile.canRead()) {
+            hdfFiles.add(hdfFile.getPath());
+        }
+    }
+
+    private static int countSlashes(String s)
+    {
+        final int N = s.length();
+        int slashcount = 0;
+        for (int i=0; i<N; i++) {
+            if (s.charAt(i) == '/') {
+                slashcount++;
+            }
+        }
+        return slashcount;
+    }
+
+    public static void write(HDF data, String templ, String filename)
+    {
+        write(data, templ, filename, false);
+    }
+
+    public static void write(HDF data, String templ, String filename, boolean fullPath)
+    {
+        if (!htmlDirs.isEmpty()) {
+            data.setValue("hasindex", "true");
+        }
+
+        String toroot;
+        if (ClearPage.toroot != null) {
+            toroot = ClearPage.toroot;
+        } else {
+            int slashcount = countSlashes(filename);
+            if (slashcount > 0) {
+                toroot = "";
+                for (int i=0; i<slashcount; i++) {
+                    toroot += "../";
+                }
+            } else {
+                toroot = "./";
+            }
+        }
+        data.setValue("toroot", toroot);
+
+        data.setValue("filename", filename);
+
+        if (!fullPath) {
+            filename = outputDir + "/" + filename;
+        }
+
+        int i=0;
+        if (!htmlDirs.isEmpty()) {
+            for (String dir : htmlDirs) {
+                data.setValue("hdf.loadpaths." + i, dir);
+                i++;
+            }
+        }
+        if (mTemplateDirSet) {
+            for (String dir: mTemplateDirs) {
+                data.setValue("hdf.loadpaths." + i, dir);
+                i++;
+            }
+        } else {
+            data.setValue("hdf.loadpaths." + i, "templates");
+        }
+        
+        CS cs = new CS(data);
+        cs.parseFile(templ);
+
+        File file = new File(outputFilename(filename));
+        
+        ensureDirectory(file);
+
+        OutputStreamWriter stream = null;
+        try {
+            stream = new OutputStreamWriter(
+                            new FileOutputStream(file), "UTF-8");
+            String rendered = cs.render();
+            stream.write(rendered, 0, rendered.length());
+        }
+        catch (IOException e) {
+            System.out.println("error: " + e.getMessage() + "; when writing file: " + filename);
+        }
+        finally {
+            if (stream != null) {
+                try {
+                    stream.close();
+                }
+                catch (IOException e) {
+                }
+            }
+        }
+    }
+
+    // recursively create the directories to the output
+    public static void ensureDirectory(File f)
+    {
+        File parent = f.getParentFile();
+        if (parent != null) {
+            parent.mkdirs();
+        }
+    }
+
+    public static void copyFile(File from, String toPath)
+    {
+        File to = new File(outputDir + "/" + toPath);
+        FileInputStream in;
+        FileOutputStream out;
+        try {
+            if (!from.exists()) {
+                throw new IOException();
+            }
+            in = new FileInputStream(from);
+        }
+        catch (IOException e) {
+            System.err.println(from.getAbsolutePath() + ": Error opening file");
+            return ;
+        }
+        ensureDirectory(to);
+        try {
+            out = new FileOutputStream(to);
+        }
+        catch (IOException e) {
+            System.err.println(from.getAbsolutePath() + ": Error opening file");
+            return ;
+        }
+
+        long sizel = from.length();
+        final int maxsize = 64*1024;
+        int size = sizel > maxsize ? maxsize : (int)sizel;
+        byte[] buf = new byte[size];
+        while (true) {
+            try {
+                size = in.read(buf);
+            }
+            catch (IOException e) {
+                System.err.println(from.getAbsolutePath()
+                        + ": error reading file");
+                break;
+            }
+            if (size > 0) {
+                try {
+                    out.write(buf, 0, size);
+                }
+                catch (IOException e) {
+                    System.err.println(from.getAbsolutePath()
+                        + ": error writing file");
+                }
+            } else {
+                break;
+            }
+        }
+        try {
+            in.close();
+        }
+        catch (IOException e) {
+        }
+        try {
+            out.close();
+        }
+        catch (IOException e) {
+        }
+    }
+    
+    /** Takes a string that ends w/ .html and changes the .html to htmlExtension */
+    public static String outputFilename(String htmlFile) {
+        if (!DroidDoc.htmlExtension.equals(".html") && htmlFile.endsWith(".html")) {
+            return htmlFile.substring(0, htmlFile.length()-5) + DroidDoc.htmlExtension;
+        } else {
+            return htmlFile;
+        }
+    }
+
+}
diff --git a/build/tools/droiddoc/src/Comment.java b/build/tools/droiddoc/src/Comment.java
new file mode 100644 (file)
index 0000000..68b6d20
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.ArrayList;
+
+public class Comment
+{
+    static final Pattern LEADING_WHITESPACE = Pattern.compile(
+                                "^[ \t\n\r]*(.*)$",
+                                Pattern.DOTALL);
+
+    static final Pattern TAG_BEGIN = Pattern.compile(
+                                "[\r\n][\r\n \t]*@",
+                                Pattern.DOTALL);
+
+    static final Pattern TAG = Pattern.compile(
+                                "(@[^ \t\r\n]+)[ \t\r\n]+(.*)",
+                                Pattern.DOTALL);
+
+    static final Pattern INLINE_TAG = Pattern.compile(
+                                "(.*?)\\{(@[^ \t\r\n\\}]+)[ \t\r\n]*(.*?)\\}",
+                                Pattern.DOTALL);
+
+    static final Pattern FIRST_SENTENCE = Pattern.compile(
+                                "((.*?)\\.)[ \t\r\n\\<](.*)",
+                                Pattern.DOTALL);
+
+    private static final String[] KNOWN_TAGS = new String[] {
+            "@author",
+            "@since",
+            "@version",
+            "@deprecated",
+            "@undeprecate",
+            "@docRoot",
+            "@sdkCurrent",
+            "@inheritDoc",
+            "@more",
+            "@code",
+            "@samplecode",
+            "@sample",
+            "@include",
+            "@serial",
+        };
+
+    public Comment(String text, ContainerInfo base, SourcePositionInfo sp)
+    {
+        mText = text;
+        mBase = base;
+        // sp now points to the end of the text, not the beginning!
+        mPosition = SourcePositionInfo.findBeginning(sp, text);
+    }
+
+    private void parseRegex(String text)
+    {
+        Matcher m;
+
+        m = LEADING_WHITESPACE.matcher(text);
+        m.matches();
+        text = m.group(1);
+
+        m = TAG_BEGIN.matcher(text);
+
+        int start = 0;
+        int end = 0;
+        while (m.find()) {
+            end = m.start();
+
+            tag(text, start, end);
+
+            start = m.end()-1; // -1 is the @
+        }
+        end = text.length();
+        tag(text, start, end);
+    }
+
+    private void tag(String text, int start, int end)
+    {
+        SourcePositionInfo pos = SourcePositionInfo.add(mPosition, mText, start);
+
+        if (start >= 0 && end > 0 && (end-start) > 0) {
+            text = text.substring(start, end);
+
+            Matcher m = TAG.matcher(text);
+            if (m.matches()) {
+                // out of line tag
+                tag(m.group(1), m.group(2), false, pos);
+            } else {
+                // look for inline tags
+                m = INLINE_TAG.matcher(text);
+                start = 0;
+                while (m.find()) {
+                    String str = m.group(1);
+                    String tagname = m.group(2);
+                    String tagvalue = m.group(3);
+                    tag(null, m.group(1), true, pos);
+                    tag(tagname, tagvalue, true, pos);
+                    start = m.end();
+                }
+                int len = text.length();
+                if (start != len) {
+                    tag(null, text.substring(start), true, pos);
+                }
+            }
+        }
+    }
+
+    private void tag(String name, String text, boolean isInline, SourcePositionInfo pos)
+    {
+        /*
+        String s = isInline ? "inline" : "outofline";
+        System.out.println("---> " + s
+                + " name=[" + name + "] text=[" + text + "]");
+        */
+        if (name == null) {
+            mInlineTagsList.add(new TextTagInfo("Text", "Text", text, pos));
+        }
+        else if (name.equals("@param")) {
+            mParamTagsList.add(new ParamTagInfo("@param", "@param", text, mBase, pos));
+        }
+        else if (name.equals("@see")) {
+            mSeeTagsList.add(new SeeTagInfo("@see", "@see", text, mBase, pos));
+        }
+        else if (name.equals("@link") || name.equals("@linkplain")) {
+            mInlineTagsList.add(new SeeTagInfo(name, "@see", text, mBase, pos));
+        }
+        else if (name.equals("@throws") || name.equals("@exception")) {
+            mThrowsTagsList.add(new ThrowsTagInfo("@throws", "@throws", text, mBase, pos));
+        }
+        else if (name.equals("@return")) {
+            mReturnTagsList.add(new ParsedTagInfo("@return", "@return", text, mBase, pos));
+        }
+        else if (name.equals("@deprecated")) {
+            if (text.length() == 0) {
+                Errors.error(Errors.MISSING_COMMENT, pos,
+                        "@deprecated tag with no explanatory comment");
+                text = "No replacement.";
+            }
+            mDeprecatedTagsList.add(new ParsedTagInfo("@deprecated", "@deprecated", text, mBase, pos));
+        }
+        else if (name.equals("@literal")) {
+            mInlineTagsList.add(new LiteralTagInfo(name, name, text, pos));
+        }
+        else if (name.equals("@hide") || name.equals("@pending") || name.equals("@doconly")) {
+            // nothing
+        }
+        else if (name.equals("@attr")) {
+            AttrTagInfo tag = new AttrTagInfo("@attr", "@attr", text, mBase, pos);
+            mAttrTagsList.add(tag);
+            Comment c = tag.description();
+            if (c != null) {
+                for (TagInfo t: c.tags()) {
+                    mInlineTagsList.add(t);
+                }
+            }
+        }
+        else if (name.equals("@undeprecate")) {
+            mUndeprecateTagsList.add(new TextTagInfo("@undeprecate", "@undeprecate", text, pos));
+        }
+        else if (name.equals("@include") || name.equals("@sample")) {
+            mInlineTagsList.add(new SampleTagInfo(name, "@include", text, mBase, pos));
+        }
+        else {
+            boolean known = false;
+            for (String s: KNOWN_TAGS) {
+                if (s.equals(name)) {
+                    known = true;
+                    break;
+                }
+            }
+            if (!known) {
+                known = DroidDoc.knownTags.contains(name);
+            }
+            if (!known) {
+                Errors.error(Errors.UNKNOWN_TAG, pos == null ? null : new SourcePositionInfo(pos),
+                        "Unknown tag: " + name);
+            }
+            TagInfo t = new TextTagInfo(name, name, text, pos);
+            if (isInline) {
+                mInlineTagsList.add(t);
+            } else {
+                mTagsList.add(t);
+            }
+        }
+    }
+
+    private void parseBriefTags()
+    {
+        int N = mInlineTagsList.size();
+
+        // look for "@more" tag, which means that we might go past the first sentence.
+        int more = -1;
+        for (int i=0; i<N; i++) {
+            if (mInlineTagsList.get(i).name().equals("@more")) {
+                more = i;
+            }
+        }
+          if (more >= 0) {
+            for (int i=0; i<more; i++) {
+                mBriefTagsList.add(mInlineTagsList.get(i));
+            }
+        } else {
+            for (int i=0; i<N; i++) {
+                TagInfo t = mInlineTagsList.get(i);
+                if (t.name().equals("Text")) {
+                    Matcher m = FIRST_SENTENCE.matcher(t.text());
+                    if (m.matches()) {
+                        String text = m.group(1);
+                        TagInfo firstSentenceTag = new TagInfo(t.name(), t.kind(), text, t.position());
+                        mBriefTagsList.add(firstSentenceTag);
+                        break;
+                    }
+                }
+                mBriefTagsList.add(t);
+
+            }
+        }
+    }
+
+    public TagInfo[] tags()
+    {
+        init();
+        return mInlineTags;
+    }
+
+    public TagInfo[] tags(String name)
+    {
+        init();
+        ArrayList<TagInfo> results = new ArrayList<TagInfo>();
+        int N = mInlineTagsList.size();
+        for (int i=0; i<N; i++) {
+            TagInfo t = mInlineTagsList.get(i);
+            if (t.name().equals(name)) {
+                results.add(t);
+            }
+        }
+        return results.toArray(new TagInfo[results.size()]);
+    }
+
+    public ParamTagInfo[] paramTags()
+    {
+        init();
+        return mParamTags;
+    }
+
+    public SeeTagInfo[] seeTags()
+    {
+        init();
+        return mSeeTags;
+    }
+
+    public ThrowsTagInfo[] throwsTags()
+    {
+        init();
+        return mThrowsTags;
+    }
+
+    public TagInfo[] returnTags()
+    {
+        init();
+        return mReturnTags;
+    }
+
+    public TagInfo[] deprecatedTags()
+    {
+        init();
+        return mDeprecatedTags;
+    }
+
+    public TagInfo[] undeprecateTags()
+    {
+        init();
+        return mUndeprecateTags;
+    }
+
+    public AttrTagInfo[] attrTags()
+    {
+        init();
+        return mAttrTags;
+    }
+
+    public TagInfo[] briefTags()
+    {
+        init();
+        return mBriefTags;
+    }
+
+    public boolean isHidden()
+    {
+        if (mHidden >= 0) {
+            return mHidden != 0;
+        } else {
+            if (DroidDoc.checkLevel(DroidDoc.SHOW_HIDDEN)) {
+                mHidden = 0;
+                return false;
+            }
+            boolean b = mText.indexOf("@hide") >= 0 || mText.indexOf("@pending") >= 0;
+            mHidden = b ? 1 : 0;
+            return b;
+        }
+    }
+
+    public boolean isDocOnly() {
+        if (mDocOnly >= 0) {
+            return mDocOnly != 0;
+        } else {
+            boolean b = (mText != null) && (mText.indexOf("@doconly") >= 0);
+            mDocOnly = b ? 1 : 0;
+            return b;
+        }
+    }
+
+    private void init()
+    {
+        if (!mInitialized) {
+            initImpl();
+        }
+    }
+
+    private void initImpl()
+    {
+        isHidden();
+        isDocOnly();
+
+        // Don't bother parsing text if we aren't generating documentation.
+        if (DroidDoc.parseComments()) {
+            parseRegex(mText);
+            parseBriefTags();
+        } else {
+          // Forces methods to be recognized by findOverriddenMethods in MethodInfo.
+          mInlineTagsList.add(new TextTagInfo("Text", "Text", mText,
+                  SourcePositionInfo.add(mPosition, mText, 0)));
+        }
+
+        mText = null;
+        mInitialized = true;
+
+        mInlineTags = mInlineTagsList.toArray(new TagInfo[mInlineTagsList.size()]);
+        mParamTags = mParamTagsList.toArray(new ParamTagInfo[mParamTagsList.size()]);
+        mSeeTags = mSeeTagsList.toArray(new SeeTagInfo[mSeeTagsList.size()]);
+        mThrowsTags = mThrowsTagsList.toArray(new ThrowsTagInfo[mThrowsTagsList.size()]);
+        mReturnTags = ParsedTagInfo.joinTags(mReturnTagsList.toArray(
+                                             new ParsedTagInfo[mReturnTagsList.size()]));
+        mDeprecatedTags = ParsedTagInfo.joinTags(mDeprecatedTagsList.toArray(
+                                        new ParsedTagInfo[mDeprecatedTagsList.size()]));
+        mUndeprecateTags = mUndeprecateTagsList.toArray(new TagInfo[mUndeprecateTagsList.size()]);
+        mAttrTags = mAttrTagsList.toArray(new AttrTagInfo[mAttrTagsList.size()]);
+        mBriefTags = mBriefTagsList.toArray(new TagInfo[mBriefTagsList.size()]);
+
+        mParamTagsList = null;
+        mSeeTagsList = null;
+        mThrowsTagsList = null;
+        mReturnTagsList = null;
+        mDeprecatedTagsList = null;
+        mUndeprecateTagsList = null;
+        mAttrTagsList = null;
+        mBriefTagsList = null;
+    }
+
+    boolean mInitialized;
+    int mHidden = -1;
+    int mDocOnly = -1;
+    String mText;
+    ContainerInfo mBase;
+    SourcePositionInfo mPosition;
+    int mLine = 1;
+
+    TagInfo[] mInlineTags;
+    TagInfo[] mTags;
+    ParamTagInfo[] mParamTags;
+    SeeTagInfo[] mSeeTags;
+    ThrowsTagInfo[] mThrowsTags;
+    TagInfo[] mBriefTags;
+    TagInfo[] mReturnTags;
+    TagInfo[] mDeprecatedTags;
+    TagInfo[] mUndeprecateTags;
+    AttrTagInfo[] mAttrTags;
+
+    ArrayList<TagInfo> mInlineTagsList = new ArrayList<TagInfo>();
+    ArrayList<TagInfo> mTagsList = new ArrayList<TagInfo>();
+    ArrayList<ParamTagInfo> mParamTagsList = new ArrayList<ParamTagInfo>();
+    ArrayList<SeeTagInfo> mSeeTagsList = new ArrayList<SeeTagInfo>();
+    ArrayList<ThrowsTagInfo> mThrowsTagsList = new ArrayList<ThrowsTagInfo>();
+    ArrayList<TagInfo> mBriefTagsList = new ArrayList<TagInfo>();
+    ArrayList<ParsedTagInfo> mReturnTagsList = new ArrayList<ParsedTagInfo>();
+    ArrayList<ParsedTagInfo> mDeprecatedTagsList = new ArrayList<ParsedTagInfo>();
+    ArrayList<TagInfo> mUndeprecateTagsList = new ArrayList<TagInfo>();
+    ArrayList<AttrTagInfo> mAttrTagsList = new ArrayList<AttrTagInfo>();
+
+
+}
diff --git a/build/tools/droiddoc/src/ContainerInfo.java b/build/tools/droiddoc/src/ContainerInfo.java
new file mode 100644 (file)
index 0000000..b8a3e10
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public interface ContainerInfo
+{
+    public String qualifiedName();
+    public boolean checkLevel();
+}
diff --git a/build/tools/droiddoc/src/Converter.java b/build/tools/droiddoc/src/Converter.java
new file mode 100644 (file)
index 0000000..ee911f4
--- /dev/null
@@ -0,0 +1,755 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.sun.javadoc.*;
+import com.sun.tools.doclets.*;
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+
+public class Converter
+{
+    private static RootDoc root;
+
+    public static void makeInfo(RootDoc r)
+    {
+        root = r;
+
+        int N, i;
+
+        // create the objects
+        ClassDoc[] classDocs = r.classes();
+        N = classDocs.length;
+        for (i=0; i<N; i++) {
+            Converter.obtainClass(classDocs[i]);
+        }
+        ArrayList<ClassInfo> classesNeedingInit2 = new ArrayList<ClassInfo>();
+        // fill in the fields that reference other classes
+        while (mClassesNeedingInit.size() > 0) {
+            i = mClassesNeedingInit.size()-1;
+            ClassNeedingInit clni = mClassesNeedingInit.get(i);
+            mClassesNeedingInit.remove(i);
+
+            initClass(clni.c, clni.cl);
+            classesNeedingInit2.add(clni.cl);
+        }
+        mClassesNeedingInit = null;
+        for (ClassInfo cl: classesNeedingInit2) {
+            cl.init2();
+        }
+
+        finishAnnotationValueInit();
+
+        // fill in the "root" stuff
+        mRootClasses = Converter.convertClasses(r.classes());
+    }
+
+    private static ClassInfo[] mRootClasses;
+    public static ClassInfo[] rootClasses()
+    {
+        return mRootClasses;
+    }
+
+    public static ClassInfo[] allClasses() {
+        return (ClassInfo[])mClasses.all();
+    }
+
+    private static void initClass(ClassDoc c, ClassInfo cl)
+    {
+        MethodDoc[] annotationElements;
+        if (c instanceof AnnotationTypeDoc) {
+            annotationElements = ((AnnotationTypeDoc)c).elements();
+        } else {
+            annotationElements = new MethodDoc[0];
+        }
+        cl.init(Converter.obtainType(c),
+                Converter.convertClasses(c.interfaces()),
+                Converter.convertTypes(c.interfaceTypes()),
+                Converter.convertClasses(c.innerClasses()),
+                Converter.convertMethods(c.constructors(false)),
+                Converter.convertMethods(c.methods(false)),
+                Converter.convertMethods(annotationElements),
+                Converter.convertFields(c.fields(false)),
+                Converter.convertFields(c.enumConstants()),
+                Converter.obtainPackage(c.containingPackage()),
+                Converter.obtainClass(c.containingClass()),
+                Converter.obtainClass(c.superclass()),
+                Converter.obtainType(c.superclassType()),
+                Converter.convertAnnotationInstances(c.annotations())
+                );
+          cl.setHiddenMethods(Converter.getHiddenMethods(c.methods(false)));
+          cl.setNonWrittenConstructors(Converter.convertNonWrittenConstructors(c.constructors(false)));
+          cl.init3(Converter.convertTypes(c.typeParameters()), Converter.convertClasses(c.innerClasses(false)));
+    }
+
+    public static ClassInfo obtainClass(String className)
+    {
+        return Converter.obtainClass(root.classNamed(className));
+    }
+
+    public static PackageInfo obtainPackage(String packageName)
+    {
+        return Converter.obtainPackage(root.packageNamed(packageName));
+    }
+
+    private static TagInfo convertTag(Tag tag)
+    {
+        return new TextTagInfo(tag.name(), tag.kind(), tag.text(),
+                                Converter.convertSourcePosition(tag.position()));
+    }
+
+    private static ThrowsTagInfo convertThrowsTag(ThrowsTag tag,
+                                                ContainerInfo base)
+    {
+        return new ThrowsTagInfo(tag.name(), tag.text(), tag.kind(),
+                              Converter.obtainClass(tag.exception()),
+                              tag.exceptionComment(), base,
+                              Converter.convertSourcePosition(tag.position()));
+    }
+
+    private static ParamTagInfo convertParamTag(ParamTag tag,
+                                                ContainerInfo base)
+    {
+        return new ParamTagInfo(tag.name(), tag.kind(), tag.text(),
+                              tag.isTypeParameter(), tag.parameterComment(),
+                              tag.parameterName(),
+                              base,
+                              Converter.convertSourcePosition(tag.position()));
+    }
+
+    private static SeeTagInfo convertSeeTag(SeeTag tag, ContainerInfo base)
+    {
+        return new SeeTagInfo(tag.name(), tag.kind(), tag.text(), base,
+                              Converter.convertSourcePosition(tag.position()));
+    }
+
+    private static SourcePositionInfo convertSourcePosition(SourcePosition sp)
+    {
+        if (sp == null) {
+            return null;
+        }
+        return new SourcePositionInfo(sp.file().toString(), sp.line(),
+                                        sp.column());
+    }
+
+    public static TagInfo[] convertTags(Tag[] tags, ContainerInfo base)
+    {
+        int len = tags.length;
+        TagInfo[] out = new TagInfo[len];
+        for (int i=0; i<len; i++) {
+            Tag t = tags[i];
+            /*
+            System.out.println("Tag name='" + t.name() + "' kind='"
+                    + t.kind() + "'");
+            */
+            if (t instanceof SeeTag) {
+                out[i] = Converter.convertSeeTag((SeeTag)t, base);
+            }
+            else if (t instanceof ThrowsTag) {
+                out[i] = Converter.convertThrowsTag((ThrowsTag)t, base);
+            }
+            else if (t instanceof ParamTag) {
+                out[i] = Converter.convertParamTag((ParamTag)t, base);
+            }
+            else {
+                out[i] = Converter.convertTag(t);
+            }
+        }
+        return out;
+    }
+
+    public static ClassInfo[] convertClasses(ClassDoc[] classes)
+    {
+        if (classes == null) return null;
+        int N = classes.length;
+        ClassInfo[] result = new ClassInfo[N];
+        for (int i=0; i<N; i++) {
+            result[i] = Converter.obtainClass(classes[i]);
+        }
+        return result;
+    }
+
+    private static ParameterInfo convertParameter(Parameter p, SourcePosition pos)
+    {
+        if (p == null) return null;
+        ParameterInfo pi = new ParameterInfo(p.name(), p.typeName(),
+                Converter.obtainType(p.type()),
+                Converter.convertSourcePosition(pos));
+        return pi;
+    }
+
+    private static ParameterInfo[] convertParameters(Parameter[] p, MemberDoc m)
+    {
+        SourcePosition pos = m.position();
+        int len = p.length;
+        ParameterInfo[] q = new ParameterInfo[len];
+        for (int i=0; i<len; i++) {
+            q[i] = Converter.convertParameter(p[i], pos);
+        }
+        return q;
+    }
+
+    private static TypeInfo[] convertTypes(Type[] p)
+    {
+        if (p == null) return null;
+        int len = p.length;
+        TypeInfo[] q = new TypeInfo[len];
+        for (int i=0; i<len; i++) {
+            q[i] = Converter.obtainType(p[i]);
+        }
+        return q;
+    }
+
+    private Converter()
+    {
+    }
+
+    private static class ClassNeedingInit
+    {
+        ClassNeedingInit(ClassDoc c, ClassInfo cl)
+        {
+            this.c = c;
+            this.cl = cl;
+        }
+        ClassDoc c;
+        ClassInfo cl;
+    };
+    private static ArrayList<ClassNeedingInit> mClassesNeedingInit
+                                            = new ArrayList<ClassNeedingInit>();
+
+    static ClassInfo obtainClass(ClassDoc o)
+    {
+        return (ClassInfo)mClasses.obtain(o);
+    }
+    private static Cache mClasses = new Cache()
+    {
+        @Override
+        protected Object make(Object o)
+        {
+            ClassDoc c = (ClassDoc)o;
+            ClassInfo cl = new ClassInfo(
+                    c,
+                    c.getRawCommentText(),
+                    Converter.convertSourcePosition(c.position()),
+                    c.isPublic(),
+                    c.isProtected(),
+                    c.isPackagePrivate(),
+                    c.isPrivate(),
+                    c.isStatic(),
+                    c.isInterface(),
+                    c.isAbstract(),
+                    c.isOrdinaryClass(),
+                    c.isException(),
+                    c.isError(),
+                    c.isEnum(),
+                    (c instanceof AnnotationTypeDoc),
+                    c.isFinal(),
+                    c.isIncluded(),
+                    c.name(),
+                    c.qualifiedName(),
+                    c.qualifiedTypeName(),
+                    c.isPrimitive());
+            if (mClassesNeedingInit != null) {
+                mClassesNeedingInit.add(new ClassNeedingInit(c, cl));
+            }
+            return cl;
+        }
+        @Override
+        protected void made(Object o, Object r)
+        {
+            if (mClassesNeedingInit == null) {
+                initClass((ClassDoc)o, (ClassInfo)r);
+                ((ClassInfo)r).init2();
+            }
+        }
+        @Override
+        ClassInfo[] all()
+        {
+            return (ClassInfo[])mCache.values().toArray(new ClassInfo[mCache.size()]);
+        }
+    };
+
+    private static MethodInfo[] getHiddenMethods(MethodDoc[] methods){
+      if (methods == null) return null;
+      ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
+      int N = methods.length;
+      for (int i=0; i<N; i++) {
+          MethodInfo m = Converter.obtainMethod(methods[i]);
+          //System.out.println(m.toString() + ": ");
+          //for (TypeInfo ti : m.getTypeParameters()){
+            //  if (ti.asClassInfo() != null){
+                //System.out.println(" " +ti.asClassInfo().toString());
+              //} else {
+                //System.out.println(" null");
+              //}
+            //}
+          if (m.isHidden()) {
+              out.add(m);
+          }
+      }
+      return out.toArray(new MethodInfo[out.size()]);
+    }
+
+    /**
+     * Convert MethodDoc[] into MethodInfo[].  Also filters according
+     * to the -private, -public option, because the filtering doesn't seem
+     * to be working in the ClassDoc.constructors(boolean) call.
+     */
+    private static MethodInfo[] convertMethods(MethodDoc[] methods)
+    {
+        if (methods == null) return null;
+        ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
+        int N = methods.length;
+        for (int i=0; i<N; i++) {
+            MethodInfo m = Converter.obtainMethod(methods[i]);
+            //System.out.println(m.toString() + ": ");
+            //for (TypeInfo ti : m.getTypeParameters()){
+              //  if (ti.asClassInfo() != null){
+                  //System.out.println(" " +ti.asClassInfo().toString());
+                //} else {
+                  //System.out.println(" null");
+                //}
+              //}
+            if (m.checkLevel()) {
+                out.add(m);
+            }
+        }
+        return out.toArray(new MethodInfo[out.size()]);
+    }
+
+    private static MethodInfo[] convertMethods(ConstructorDoc[] methods)
+    {
+        if (methods == null) return null;
+        ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
+        int N = methods.length;
+        for (int i=0; i<N; i++) {
+            MethodInfo m = Converter.obtainMethod(methods[i]);
+            if (m.checkLevel()) {
+                out.add(m);
+            }
+        }
+        return out.toArray(new MethodInfo[out.size()]);
+    }
+
+    private static MethodInfo[] convertNonWrittenConstructors(ConstructorDoc[] methods)
+    {
+        if (methods == null) return null;
+        ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
+        int N = methods.length;
+        for (int i=0; i<N; i++) {
+            MethodInfo m = Converter.obtainMethod(methods[i]);
+            if (!m.checkLevel()) {
+                out.add(m);
+            }
+        }
+        return out.toArray(new MethodInfo[out.size()]);
+    }
+
+    private static MethodInfo obtainMethod(MethodDoc o)
+    {
+        return (MethodInfo)mMethods.obtain(o);
+    }
+    private static MethodInfo obtainMethod(ConstructorDoc o)
+    {
+        return (MethodInfo)mMethods.obtain(o);
+    }
+    private static Cache mMethods = new Cache()
+    {
+        @Override
+        protected Object make(Object o)
+        {
+            if (o instanceof AnnotationTypeElementDoc) {
+                AnnotationTypeElementDoc m = (AnnotationTypeElementDoc)o;
+                MethodInfo result = new MethodInfo(
+                                m.getRawCommentText(),
+                                Converter.convertTypes(m.typeParameters()),
+                                m.name(), m.signature(),
+                                Converter.obtainClass(m.containingClass()),
+                                Converter.obtainClass(m.containingClass()),
+                                m.isPublic(), m.isProtected(),
+                                m.isPackagePrivate(), m.isPrivate(),
+                                m.isFinal(), m.isStatic(), m.isSynthetic(),
+                                m.isAbstract(), m.isSynchronized(), m.isNative(), true,
+                                "annotationElement",
+                                m.flatSignature(),
+                                Converter.obtainMethod(m.overriddenMethod()),
+                                Converter.obtainType(m.returnType()),
+                                Converter.convertParameters(m.parameters(), m),
+                                Converter.convertClasses(m.thrownExceptions()),
+                                Converter.convertSourcePosition(m.position()),
+                                Converter.convertAnnotationInstances(m.annotations())
+                            );
+                result.setVarargs(m.isVarArgs());
+                result.init(Converter.obtainAnnotationValue(m.defaultValue(), result));
+                return result;
+            }
+            else if (o instanceof MethodDoc) {
+                MethodDoc m = (MethodDoc)o;
+                MethodInfo result = new MethodInfo(
+                                m.getRawCommentText(),
+                                Converter.convertTypes(m.typeParameters()),
+                                m.name(), m.signature(),
+                                Converter.obtainClass(m.containingClass()),
+                                Converter.obtainClass(m.containingClass()),
+                                m.isPublic(), m.isProtected(),
+                                m.isPackagePrivate(), m.isPrivate(),
+                                m.isFinal(), m.isStatic(), m.isSynthetic(),
+                                m.isAbstract(), m.isSynchronized(), m.isNative(), false,
+                                "method",
+                                m.flatSignature(),
+                                Converter.obtainMethod(m.overriddenMethod()),
+                                Converter.obtainType(m.returnType()),
+                                Converter.convertParameters(m.parameters(), m),
+                                Converter.convertClasses(m.thrownExceptions()),
+                                Converter.convertSourcePosition(m.position()),
+                                Converter.convertAnnotationInstances(m.annotations())
+                           );
+                result.setVarargs(m.isVarArgs());
+                result.init(null);
+                return result;
+            }
+            else {
+                ConstructorDoc m = (ConstructorDoc)o;
+                MethodInfo result = new MethodInfo(
+                                m.getRawCommentText(),
+                                Converter.convertTypes(m.typeParameters()),
+                                m.name(), m.signature(),
+                                Converter.obtainClass(m.containingClass()),
+                                Converter.obtainClass(m.containingClass()),
+                                m.isPublic(), m.isProtected(),
+                                m.isPackagePrivate(), m.isPrivate(),
+                                m.isFinal(), m.isStatic(), m.isSynthetic(),
+                                false, m.isSynchronized(), m.isNative(), false,
+                                "constructor",
+                                m.flatSignature(),
+                                null,
+                                null,
+                                Converter.convertParameters(m.parameters(), m),
+                                Converter.convertClasses(m.thrownExceptions()),
+                                Converter.convertSourcePosition(m.position()),
+                                Converter.convertAnnotationInstances(m.annotations())
+                            );
+                result.setVarargs(m.isVarArgs());
+                result.init(null);
+                return result;
+            }
+        }
+    };
+
+
+    private static FieldInfo[] convertFields(FieldDoc[] fields)
+    {
+        if (fields == null) return null;
+        ArrayList<FieldInfo> out = new ArrayList<FieldInfo>();
+        int N = fields.length;
+        for (int i=0; i<N; i++) {
+            FieldInfo f = Converter.obtainField(fields[i]);
+            if (f.checkLevel()) {
+                out.add(f);
+            }
+        }
+        return out.toArray(new FieldInfo[out.size()]);
+    }
+
+    private static FieldInfo obtainField(FieldDoc o)
+    {
+        return (FieldInfo)mFields.obtain(o);
+    }
+    private static FieldInfo obtainField(ConstructorDoc o)
+    {
+        return (FieldInfo)mFields.obtain(o);
+    }
+    private static Cache mFields = new Cache()
+    {
+        @Override
+        protected Object make(Object o)
+        {
+            FieldDoc f = (FieldDoc)o;
+            return new FieldInfo(f.name(),
+                            Converter.obtainClass(f.containingClass()),
+                            Converter.obtainClass(f.containingClass()),
+                            f.isPublic(), f.isProtected(),
+                            f.isPackagePrivate(), f.isPrivate(),
+                            f.isFinal(), f.isStatic(), f.isTransient(), f.isVolatile(),
+                            f.isSynthetic(),
+                            Converter.obtainType(f.type()),
+                            f.getRawCommentText(), f.constantValue(),
+                            Converter.convertSourcePosition(f.position()),
+                            Converter.convertAnnotationInstances(f.annotations())
+                        );
+        }
+    };
+
+    private static PackageInfo obtainPackage(PackageDoc o)
+    {
+        return (PackageInfo)mPackagees.obtain(o);
+    }
+    private static Cache mPackagees = new Cache()
+    {
+        @Override
+        protected Object make(Object o)
+        {
+            PackageDoc p = (PackageDoc)o;
+            return new PackageInfo(p, p.name(),
+                    Converter.convertSourcePosition(p.position()));
+        }
+    };
+
+    private static TypeInfo obtainType(Type o)
+    {
+        return (TypeInfo)mTypes.obtain(o);
+    }
+    private static Cache mTypes = new Cache()
+    {
+       @Override
+    protected Object make(Object o)
+       {
+           Type t = (Type)o;
+           String simpleTypeName;
+           if (t instanceof ClassDoc) {
+               simpleTypeName = ((ClassDoc)t).name();
+           } else {
+               simpleTypeName = t.simpleTypeName();
+           }
+           TypeInfo ti = new TypeInfo(t.isPrimitive(), t.dimension(),
+                   simpleTypeName, t.qualifiedTypeName(),
+                   Converter.obtainClass(t.asClassDoc()));
+           return ti;
+       }
+        @Override
+        protected void made(Object o, Object r)
+        {
+            Type t = (Type)o;
+            TypeInfo ti = (TypeInfo)r;
+            if (t.asParameterizedType() != null) {
+                ti.setTypeArguments(Converter.convertTypes(
+                            t.asParameterizedType().typeArguments()));
+            }
+            else if (t instanceof ClassDoc) {
+                ti.setTypeArguments(Converter.convertTypes(((ClassDoc)t).typeParameters()));
+            }
+            else if (t.asTypeVariable() != null) {
+                ti.setBounds(null, Converter.convertTypes((t.asTypeVariable().bounds())));
+                ti.setIsTypeVariable(true);
+            }
+            else if (t.asWildcardType() != null) {
+                ti.setIsWildcard(true);
+                ti.setBounds(Converter.convertTypes(t.asWildcardType().superBounds()),
+                             Converter.convertTypes(t.asWildcardType().extendsBounds()));
+            }
+        }
+        @Override
+        protected Object keyFor(Object o)
+        {
+            Type t = (Type)o;
+            String keyString = o.getClass().getName() + "/" + o.toString() + "/";
+            if (t.asParameterizedType() != null){
+              keyString += t.asParameterizedType().toString() +"/";
+              if (t.asParameterizedType().typeArguments() != null){
+              for(Type ty : t.asParameterizedType().typeArguments()){
+                keyString += ty.toString() + "/";
+              }
+              }
+            }else{
+              keyString += "NoParameterizedType//";
+            }
+            if (t.asTypeVariable() != null){
+              keyString += t.asTypeVariable().toString() +"/";
+              if (t.asTypeVariable().bounds() != null){
+              for(Type ty : t.asTypeVariable().bounds()){
+                keyString += ty.toString() + "/";
+              }
+              }
+            }else{
+              keyString += "NoTypeVariable//";
+            }
+            if (t.asWildcardType() != null){
+              keyString += t.asWildcardType().toString() +"/";
+              if (t.asWildcardType().superBounds() != null){
+              for(Type ty : t.asWildcardType().superBounds()){
+                keyString += ty.toString() + "/";
+              }
+              }
+              if (t.asWildcardType().extendsBounds() != null){
+                for(Type ty : t.asWildcardType().extendsBounds()){
+                  keyString += ty.toString() + "/";
+                }
+                }
+            }else{
+              keyString += "NoWildCardType//";
+            }
+
+
+
+            return keyString;
+        }
+    };
+
+
+
+    private static MemberInfo obtainMember(MemberDoc o)
+    {
+        return (MemberInfo)mMembers.obtain(o);
+    }
+    private static Cache mMembers = new Cache()
+    {
+        @Override
+        protected Object make(Object o)
+        {
+            if (o instanceof MethodDoc) {
+                return Converter.obtainMethod((MethodDoc)o);
+            }
+            else if (o instanceof ConstructorDoc) {
+                return Converter.obtainMethod((ConstructorDoc)o);
+            }
+            else if (o instanceof FieldDoc) {
+                return Converter.obtainField((FieldDoc)o);
+            }
+            else {
+                return null;
+            }
+        }
+    };
+
+    private static AnnotationInstanceInfo[] convertAnnotationInstances(AnnotationDesc[] orig)
+    {
+        int len = orig.length;
+        AnnotationInstanceInfo[] out = new AnnotationInstanceInfo[len];
+        for (int i=0; i<len; i++) {
+            out[i] = Converter.obtainAnnotationInstance(orig[i]);
+        }
+        return out;
+    }
+
+
+    private static AnnotationInstanceInfo obtainAnnotationInstance(AnnotationDesc o)
+    {
+        return (AnnotationInstanceInfo)mAnnotationInstances.obtain(o);
+    }
+    private static Cache mAnnotationInstances = new Cache()
+    {
+        @Override
+        protected Object make(Object o)
+        {
+            AnnotationDesc a = (AnnotationDesc)o;
+            ClassInfo annotationType = Converter.obtainClass(a.annotationType());
+            AnnotationDesc.ElementValuePair[] ev = a.elementValues();
+            AnnotationValueInfo[] elementValues = new AnnotationValueInfo[ev.length];
+            for (int i=0; i<ev.length; i++) {
+                elementValues[i] = obtainAnnotationValue(ev[i].value(),
+                                            Converter.obtainMethod(ev[i].element()));
+            }
+            return new AnnotationInstanceInfo(annotationType, elementValues);
+        }
+    };
+
+
+    private abstract static class Cache
+    {
+        void put(Object key, Object value)
+        {
+            mCache.put(key, value);
+        }
+        Object obtain(Object o)
+        {
+            if (o == null ) {
+                return null;
+            }
+            Object k = keyFor(o);
+            Object r = mCache.get(k);
+            if (r == null) {
+                r = make(o);
+                mCache.put(k, r);
+                made(o, r);
+            }
+            return r;
+        }
+        protected HashMap<Object,Object> mCache = new HashMap<Object,Object>();
+        protected abstract Object make(Object o);
+        protected void made(Object o, Object r)
+        {
+        }
+        protected Object keyFor(Object o) { return o; }
+        Object[] all() { return null; }
+    }
+
+    // annotation values
+    private static HashMap<AnnotationValue,AnnotationValueInfo> mAnnotationValues = new HashMap();
+    private static HashSet<AnnotationValue> mAnnotationValuesNeedingInit = new HashSet();
+
+    private static AnnotationValueInfo obtainAnnotationValue(AnnotationValue o, MethodInfo element)
+    {
+        if (o == null) {
+            return null;
+        }
+        AnnotationValueInfo v = mAnnotationValues.get(o);
+        if (v != null) return v;
+        v = new AnnotationValueInfo(element);
+        mAnnotationValues.put(o, v);
+        if (mAnnotationValuesNeedingInit != null) {
+            mAnnotationValuesNeedingInit.add(o);
+        } else {
+            initAnnotationValue(o, v);
+        }
+        return v;
+    }
+
+    private static void initAnnotationValue(AnnotationValue o, AnnotationValueInfo v) {
+        Object orig = o.value();
+        Object converted;
+        if (orig instanceof Type) {
+            // class literal
+            converted = Converter.obtainType((Type)orig);
+        }
+        else if (orig instanceof FieldDoc) {
+            // enum constant
+            converted = Converter.obtainField((FieldDoc)orig);
+        }
+        else if (orig instanceof AnnotationDesc) {
+            // annotation instance
+            converted = Converter.obtainAnnotationInstance((AnnotationDesc)orig);
+        }
+        else if (orig instanceof AnnotationValue[]) {
+            AnnotationValue[] old = (AnnotationValue[])orig;
+            AnnotationValueInfo[] array = new AnnotationValueInfo[old.length];
+            for (int i=0; i<array.length; i++) {
+                array[i] = Converter.obtainAnnotationValue(old[i], null);
+            }
+            converted = array;
+        }
+        else {
+            converted = orig;
+        }
+        v.init(converted);
+    }
+
+    private static void finishAnnotationValueInit()
+    {
+        int depth = 0;
+        while (mAnnotationValuesNeedingInit.size() > 0) {
+            HashSet<AnnotationValue> set = mAnnotationValuesNeedingInit;
+            mAnnotationValuesNeedingInit = new HashSet();
+            for (AnnotationValue o: set) {
+                AnnotationValueInfo v = mAnnotationValues.get(o);
+                initAnnotationValue(o, v);
+            }
+            depth++;
+        }
+        mAnnotationValuesNeedingInit = null;
+    }
+}
diff --git a/build/tools/droiddoc/src/DocFile.java b/build/tools/droiddoc/src/DocFile.java
new file mode 100644 (file)
index 0000000..cc7a8cf
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+import java.util.*;
+import java.io.*;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+
+public class DocFile
+{
+    private static final Pattern LINE = Pattern.compile("(.*)[\r]?\n",
+                                                        Pattern.MULTILINE);
+    private static final Pattern PROP = Pattern.compile("([^=]+)=(.*)");
+
+    public static String readFile(String filename)
+    {
+        try {
+            File f = new File(filename);
+            int length = (int)f.length();
+            FileInputStream is = new FileInputStream(f);
+            InputStreamReader reader = new InputStreamReader(is, "UTF-8");
+            char[] buf = new char[length];
+            int index = 0;
+            int amt;
+            while (true) {
+                amt = reader.read(buf, index, length-index);
+
+                if (amt < 1) {
+                    break;
+                }
+
+                index += amt;
+            }
+            return new String(buf, 0, index);
+        }
+        catch (IOException e) {
+            return null;
+        }
+    }
+
+    public static void writePage(String docfile, String relative,
+                                    String outfile)
+    {
+        HDF hdf = DroidDoc.makeHDF();
+
+        /*
+        System.out.println("docfile='" + docfile
+                            + "' relative='" + relative + "'"
+                            + "' outfile='" + outfile + "'");
+        */
+
+        String filedata = readFile(docfile);
+
+        // The document is properties up until the line "@jd:body".
+        // Any blank lines are ignored.
+        int start = -1;
+        int lineno = 1;
+        Matcher lines = LINE.matcher(filedata);
+        String line = null;
+        while (lines.find()) {
+            line = lines.group(1);
+            if (line.length() > 0) {
+                if (line.equals("@jd:body")) {
+                    start = lines.end();
+                    break;
+                }
+                Matcher prop = PROP.matcher(line);
+                if (prop.matches()) {
+                    String key = prop.group(1);
+                    String value = prop.group(2);
+                    hdf.setValue(key, value);
+                } else {
+                    break;
+                }
+            }
+            lineno++;
+        }
+        if (start < 0) {
+            System.err.println(docfile + ":" + lineno + ": error parsing docfile");
+            if (line != null) {
+                System.err.println(docfile + ":" + lineno + ":" + line);
+            }
+            System.exit(1);
+        }
+
+        // if they asked to only be for a certain template, maybe skip it
+        String fromTemplate = hdf.getValue("template.which", "");
+        String fromPage = hdf.getValue("page.onlyfortemplate", "");
+        if (!"".equals(fromPage) && !fromTemplate.equals(fromPage)) {
+            return;
+        }
+
+        // and the actual text after that
+        String commentText = filedata.substring(start);
+
+        Comment comment = new Comment(commentText, null,
+                                    new SourcePositionInfo(docfile, lineno, 1));
+        TagInfo[] tags = comment.tags();
+
+        TagInfo.makeHDF(hdf, "root.descr", tags);
+
+        hdf.setValue("commentText", commentText);
+
+        // write the page using the appropriate root template, based on the 
+        // whichdoc value supplied by build
+        String fromWhichmodule = hdf.getValue("android.whichmodule", "");
+        if (fromWhichmodule.equals("online-pdk")) {
+            //leaving this in just for temporary compatibility with pdk doc
+            hdf.setValue("online-pdk", "true");
+            // add any conditional login for root template here (such as 
+            // for custom left nav based on tab etc. 
+            ClearPage.write(hdf, "docpage.cs", outfile);
+        } else {
+            if (outfile.indexOf("sdk/") != -1) {
+                hdf.setValue("sdk", "true");
+                if ((outfile.indexOf("index.html") != -1) || (outfile.indexOf("features.html") != -1)) {
+                    ClearPage.write(hdf, "sdkpage.cs", outfile);
+                } else {
+                    ClearPage.write(hdf, "docpage.cs", outfile);
+                }
+            } else if (outfile.indexOf("guide/") != -1) {
+                hdf.setValue("guide", "true");
+                ClearPage.write(hdf, "docpage.cs", outfile);
+            } else if (outfile.indexOf("resources/") != -1) {
+                hdf.setValue("resources", "true");
+                ClearPage.write(hdf, "docpage.cs", outfile);
+            } else {
+                ClearPage.write(hdf, "nosidenavpage.cs", outfile);
+            }
+        }
+    } //writePage
+}
diff --git a/build/tools/droiddoc/src/DocInfo.java b/build/tools/droiddoc/src/DocInfo.java
new file mode 100644 (file)
index 0000000..3abb367
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public abstract class DocInfo
+{
+    public DocInfo(String rawCommentText, SourcePositionInfo sp)
+    {
+        mRawCommentText = rawCommentText;
+        mPosition = sp;
+    }
+
+    public boolean isHidden()
+    {
+        return comment().isHidden();
+    }
+
+    public boolean isDocOnly() {
+        return comment().isDocOnly();
+    }
+    
+    public String getRawCommentText()
+    {
+        return mRawCommentText;
+    }
+
+    public Comment comment()
+    {
+        if (mComment == null) {
+            mComment = new Comment(mRawCommentText, parent(), mPosition);
+        }
+        return mComment;
+    }
+
+    public SourcePositionInfo position()
+    {
+        return mPosition;
+    }
+
+    public abstract ContainerInfo parent();
+
+    public void setSince(String since) {
+        mSince = since;
+    }
+
+    public String getSince() {
+        return mSince;
+    }
+
+    private String mRawCommentText;
+    Comment mComment;
+    SourcePositionInfo mPosition;
+    private String mSince;
+}
+
diff --git a/build/tools/droiddoc/src/DroidDoc.java b/build/tools/droiddoc/src/DroidDoc.java
new file mode 100644 (file)
index 0000000..dfdbda6
--- /dev/null
@@ -0,0 +1,1465 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.sun.javadoc.*;
+
+import org.clearsilver.HDF;
+
+import java.util.*;
+import java.io.*;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class DroidDoc
+{
+    private static final String SDK_CONSTANT_ANNOTATION = "android.annotation.SdkConstant";
+    private static final String SDK_CONSTANT_TYPE_ACTIVITY_ACTION = "android.annotation.SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION";
+    private static final String SDK_CONSTANT_TYPE_BROADCAST_ACTION = "android.annotation.SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION";
+    private static final String SDK_CONSTANT_TYPE_SERVICE_ACTION = "android.annotation.SdkConstant.SdkConstantType.SERVICE_INTENT_ACTION";
+    private static final String SDK_CONSTANT_TYPE_CATEGORY = "android.annotation.SdkConstant.SdkConstantType.INTENT_CATEGORY";
+    private static final String SDK_CONSTANT_TYPE_FEATURE = "android.annotation.SdkConstant.SdkConstantType.FEATURE";
+    private static final String SDK_WIDGET_ANNOTATION = "android.annotation.Widget";
+    private static final String SDK_LAYOUT_ANNOTATION = "android.annotation.Layout";
+
+    private static final int TYPE_NONE = 0;
+    private static final int TYPE_WIDGET = 1;
+    private static final int TYPE_LAYOUT = 2;
+    private static final int TYPE_LAYOUT_PARAM = 3;
+
+    public static final int SHOW_PUBLIC = 0x00000001;
+    public static final int SHOW_PROTECTED = 0x00000003;
+    public static final int SHOW_PACKAGE = 0x00000007;
+    public static final int SHOW_PRIVATE = 0x0000000f;
+    public static final int SHOW_HIDDEN = 0x0000001f;
+
+    public static int showLevel = SHOW_PROTECTED;
+
+    public static final String javadocDir = "reference/";
+    public static String htmlExtension;
+
+    public static RootDoc root;
+    public static ArrayList<String[]> mHDFData = new ArrayList<String[]>();
+    public static Map<Character,String> escapeChars = new HashMap<Character,String>();
+    public static String title = "";
+    public static SinceTagger sinceTagger = new SinceTagger();
+    public static HashSet<String> knownTags = new HashSet<String>();
+
+    private static boolean parseComments = false;
+    private static boolean generateDocs = true;
+    
+    /**
+    * Returns true if we should parse javadoc comments,
+    * reporting errors in the process.
+    */
+    public static boolean parseComments() {
+        return generateDocs || parseComments;
+    }
+
+    public static boolean checkLevel(int level)
+    {
+        return (showLevel & level) == level;
+    }
+
+    public static boolean checkLevel(boolean pub, boolean prot, boolean pkgp,
+            boolean priv, boolean hidden)
+    {
+        int level = 0;
+        if (hidden && !checkLevel(SHOW_HIDDEN)) {
+            return false;
+        }
+        if (pub && checkLevel(SHOW_PUBLIC)) {
+            return true;
+        }
+        if (prot && checkLevel(SHOW_PROTECTED)) {
+            return true;
+        }
+        if (pkgp && checkLevel(SHOW_PACKAGE)) {
+            return true;
+        }
+        if (priv && checkLevel(SHOW_PRIVATE)) {
+            return true;
+        }
+        return false;
+    }
+
+    public static boolean start(RootDoc r)
+    {
+        String keepListFile = null;
+        String proofreadFile = null;
+        String todoFile = null;
+        String sdkValuePath = null;
+        ArrayList<SampleCode> sampleCodes = new ArrayList<SampleCode>();
+        String stubsDir = null;
+        //Create the dependency graph for the stubs directory
+        boolean apiXML = false;
+        boolean offlineMode = false;
+        String apiFile = null;
+        String debugStubsFile = "";
+        HashSet<String> stubPackages = null;
+        ArrayList<String> knownTagsFiles = new ArrayList<String>();
+
+        root = r;
+
+        String[][] options = r.options();
+        for (String[] a: options) {
+            if (a[0].equals("-d")) {
+                ClearPage.outputDir = a[1];
+            }
+            else if (a[0].equals("-templatedir")) {
+                ClearPage.addTemplateDir(a[1]);
+            }
+            else if (a[0].equals("-hdf")) {
+                mHDFData.add(new String[] {a[1], a[2]});
+            }
+            else if (a[0].equals("-knowntags")) {
+                knownTagsFiles.add(a[1]);
+            }
+            else if (a[0].equals("-toroot")) {
+                ClearPage.toroot = a[1];
+            }
+            else if (a[0].equals("-samplecode")) {
+                sampleCodes.add(new SampleCode(a[1], a[2], a[3]));
+            }
+            else if (a[0].equals("-htmldir")) {
+                ClearPage.htmlDirs.add(a[1]);
+            }
+            else if (a[0].equals("-title")) {
+                DroidDoc.title = a[1];
+            }
+            else if (a[0].equals("-werror")) {
+                Errors.setWarningsAreErrors(true);
+            }
+            else if (a[0].equals("-error") || a[0].equals("-warning")
+                    || a[0].equals("-hide")) {
+                try {
+                    int level = -1;
+                    if (a[0].equals("-error")) {
+                        level = Errors.ERROR;
+                    }
+                    else if (a[0].equals("-warning")) {
+                        level = Errors.WARNING;
+                    }
+                    else if (a[0].equals("-hide")) {
+                        level = Errors.HIDDEN;
+                    }
+                    Errors.setErrorLevel(Integer.parseInt(a[1]), level);
+                }
+                catch (NumberFormatException e) {
+                    // already printed below
+                    return false;
+                }
+            }
+            else if (a[0].equals("-keeplist")) {
+                keepListFile = a[1];
+            }
+            else if (a[0].equals("-proofread")) {
+                proofreadFile = a[1];
+            }
+            else if (a[0].equals("-todo")) {
+                todoFile = a[1];
+            }
+            else if (a[0].equals("-public")) {
+                showLevel = SHOW_PUBLIC;
+            }
+            else if (a[0].equals("-protected")) {
+                showLevel = SHOW_PROTECTED;
+            }
+            else if (a[0].equals("-package")) {
+                showLevel = SHOW_PACKAGE;
+            }
+            else if (a[0].equals("-private")) {
+                showLevel = SHOW_PRIVATE;
+            }
+            else if (a[0].equals("-hidden")) {
+                showLevel = SHOW_HIDDEN;
+            }
+            else if (a[0].equals("-stubs")) {
+                stubsDir = a[1];
+            }
+            else if (a[0].equals("-stubpackages")) {
+                stubPackages = new HashSet();
+                for (String pkg: a[1].split(":")) {
+                    stubPackages.add(pkg);
+                }
+            }
+            else if (a[0].equals("-sdkvalues")) {
+                sdkValuePath = a[1];
+            }
+            else if (a[0].equals("-apixml")) {
+                apiXML = true;
+                apiFile = a[1];
+            }
+            else if (a[0].equals("-nodocs")) {
+                generateDocs = false;
+            }
+            else if (a[0].equals("-parsecomments")) {
+                parseComments = true;
+            }
+            else if (a[0].equals("-since")) {
+                sinceTagger.addVersion(a[1], a[2]);
+            }
+            else if (a[0].equals("-offlinemode")) {
+                offlineMode = true;
+            }
+        }
+
+        if (!readKnownTagsFiles(knownTags, knownTagsFiles)) {
+            return false;
+        }
+
+        // read some prefs from the template
+        if (!readTemplateSettings()) {
+            return false;
+        }
+
+        // Set up the data structures
+        Converter.makeInfo(r);
+
+        if (generateDocs) {
+            long startTime = System.nanoTime();
+
+            // Apply @since tags from the XML file
+            sinceTagger.tagAll(Converter.rootClasses());
+
+            // Files for proofreading
+            if (proofreadFile != null) {
+                Proofread.initProofread(proofreadFile);
+            }
+            if (todoFile != null) {
+                TodoFile.writeTodoFile(todoFile);
+            }
+
+            // HTML Pages
+            if (!ClearPage.htmlDirs.isEmpty()) {
+                writeHTMLPages();
+            }
+
+            // Navigation tree
+            NavTree.writeNavTree(javadocDir);
+
+            // Packages Pages
+            writePackages(javadocDir
+                            + (!ClearPage.htmlDirs.isEmpty()
+                                ? "packages" + htmlExtension
+                                : "index" + htmlExtension));
+
+            // Classes
+            writeClassLists();
+            writeClasses();
+            writeHierarchy();
+     //      writeKeywords();
+
+            // Lists for JavaScript
+            writeLists();
+            if (keepListFile != null) {
+                writeKeepList(keepListFile);
+            }
+
+            // Sample Code
+            for (SampleCode sc: sampleCodes) {
+                sc.write(offlineMode);
+            }
+
+            // Index page
+            writeIndex();
+
+            Proofread.finishProofread(proofreadFile);
+
+            if (sdkValuePath != null) {
+                writeSdkValues(sdkValuePath);
+            }
+
+            long time = System.nanoTime() - startTime;
+            System.out.println("DroidDoc took " + (time / 1000000000) + " sec. to write docs to "
+                    + ClearPage.outputDir);
+        }
+
+        // Stubs
+        if (stubsDir != null) {
+            Stubs.writeStubs(stubsDir, apiXML, apiFile, stubPackages);
+        }
+
+        Errors.printErrors();
+        return !Errors.hadError;
+    }
+
+    private static void writeIndex() {
+        HDF data = makeHDF();
+        ClearPage.write(data, "index.cs", javadocDir + "index" + htmlExtension);
+    }
+
+    private static boolean readTemplateSettings()
+    {
+        HDF data = makeHDF();
+        htmlExtension = data.getValue("template.extension", ".html");
+        int i=0;
+        while (true) {
+            String k = data.getValue("template.escape." + i + ".key", "");
+            String v = data.getValue("template.escape." + i + ".value", "");
+            if ("".equals(k)) {
+                break;
+            }
+            if (k.length() != 1) {
+                System.err.println("template.escape." + i + ".key must have a length of 1: " + k);
+                return false;
+            }
+            escapeChars.put(k.charAt(0), v);
+            i++;
+        }
+        return true;
+    }
+
+    private static boolean readKnownTagsFiles(HashSet<String> knownTags,
+            ArrayList<String> knownTagsFiles) {
+        for (String fn: knownTagsFiles) {
+            BufferedReader in = null;
+            try {
+                in = new BufferedReader(new FileReader(fn));
+                int lineno = 0;
+                boolean fail = false;
+                while (true) {
+                    lineno++;
+                    String line = in.readLine();
+                    if (line == null) {
+                        break;
+                    }
+                    line = line.trim();
+                    if (line.length() == 0) {
+                        continue;
+                    } else if (line.charAt(0) == '#') {
+                        continue;
+                    }
+                    String[] words = line.split("\\s+", 2);
+                    if (words.length == 2) {
+                        if (words[1].charAt(0) != '#') {
+                            System.err.println(fn + ":" + lineno
+                                    + ": Only one tag allowed per line: " + line);
+                            fail = true;
+                            continue;
+                        }
+                    }
+                    knownTags.add(words[0]);
+                }
+                if (fail) {
+                    return false;
+                }
+            } catch (IOException ex) {
+                System.err.println("Error reading file: " + fn + " (" + ex.getMessage() + ")");
+                return false;
+            } finally {
+                if (in != null) {
+                    try {
+                        in.close();
+                    } catch (IOException e) {
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    public static String escape(String s) {
+        if (escapeChars.size() == 0) {
+            return s;
+        }
+        StringBuffer b = null;
+        int begin = 0;
+        final int N = s.length();
+        for (int i=0; i<N; i++) {
+            char c = s.charAt(i);
+            String mapped = escapeChars.get(c);
+            if (mapped != null) {
+                if (b == null) {
+                    b = new StringBuffer(s.length() + mapped.length());
+                }
+                if (begin != i) {
+                    b.append(s.substring(begin, i));
+                }
+                b.append(mapped);
+                begin = i+1;
+            }
+        }
+        if (b != null) {
+            if (begin != N) {
+                b.append(s.substring(begin, N));
+            }
+            return b.toString();
+        }
+        return s;
+    }
+
+    public static void setPageTitle(HDF data, String title)
+    {
+        String s = title;
+        if (DroidDoc.title.length() > 0) {
+            s += " - " + DroidDoc.title;
+        }
+        data.setValue("page.title", s);
+    }
+
+    public static LanguageVersion languageVersion()
+    {
+        return LanguageVersion.JAVA_1_5;
+    }
+
+    public static int optionLength(String option)
+    {
+        if (option.equals("-d")) {
+            return 2;
+        }
+        if (option.equals("-templatedir")) {
+            return 2;
+        }
+        if (option.equals("-hdf")) {
+            return 3;
+        }
+        if (option.equals("-knowntags")) {
+            return 2;
+        }
+        if (option.equals("-toroot")) {
+            return 2;
+        }
+        if (option.equals("-samplecode")) {
+            return 4;
+        }
+        if (option.equals("-htmldir")) {
+            return 2;
+        }
+        if (option.equals("-title")) {
+            return 2;
+        }
+        if (option.equals("-werror")) {
+            return 1;
+        }
+        if (option.equals("-hide")) {
+            return 2;
+        }
+        if (option.equals("-warning")) {
+            return 2;
+        }
+        if (option.equals("-error")) {
+            return 2;
+        }
+        if (option.equals("-keeplist")) {
+            return 2;
+        }
+        if (option.equals("-proofread")) {
+            return 2;
+        }
+        if (option.equals("-todo")) {
+            return 2;
+        }
+        if (option.equals("-public")) {
+            return 1;
+        }
+        if (option.equals("-protected")) {
+            return 1;
+        }
+        if (option.equals("-package")) {
+            return 1;
+        }
+        if (option.equals("-private")) {
+            return 1;
+        }
+        if (option.equals("-hidden")) {
+            return 1;
+        }
+        if (option.equals("-stubs")) {
+            return 2;
+        }
+        if (option.equals("-stubpackages")) {
+            return 2;
+        }
+        if (option.equals("-sdkvalues")) {
+            return 2;
+        }
+        if (option.equals("-apixml")) {
+            return 2;
+        }
+        if (option.equals("-nodocs")) {
+            return 1;
+        }
+        if (option.equals("-parsecomments")) {
+            return 1;
+        }
+        if (option.equals("-since")) {
+            return 3;
+        }
+        if (option.equals("-offlinemode")) {
+            return 1;
+        }
+        return 0;
+    }
+
+    public static boolean validOptions(String[][] options, DocErrorReporter r)
+    {
+        for (String[] a: options) {
+            if (a[0].equals("-error") || a[0].equals("-warning")
+                    || a[0].equals("-hide")) {
+                try {
+                    Integer.parseInt(a[1]);
+                }
+                catch (NumberFormatException e) {
+                    r.printError("bad -" + a[0] + " value must be a number: "
+                            + a[1]);
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    public static HDF makeHDF()
+    {
+        HDF data = new HDF();
+
+        for (String[] p: mHDFData) {
+            data.setValue(p[0], p[1]);
+        }
+
+        try {
+            for (String p: ClearPage.hdfFiles) {
+                data.readFile(p);
+            }
+        }
+        catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+
+        return data;
+    }
+
+    public static HDF makePackageHDF()
+    {
+        HDF data = makeHDF();
+        ClassInfo[] classes = Converter.rootClasses();
+
+        SortedMap<String, PackageInfo> sorted = new TreeMap<String, PackageInfo>();
+        for (ClassInfo cl: classes) {
+            PackageInfo pkg = cl.containingPackage();
+            String name;
+            if (pkg == null) {
+                name = "";
+            } else {
+                name = pkg.name();
+            }
+            sorted.put(name, pkg);
+        }
+
+        int i = 0;
+        for (String s: sorted.keySet()) {
+            PackageInfo pkg = sorted.get(s);
+
+            if (pkg.isHidden()) {
+                continue;
+            }
+            Boolean allHidden = true;
+            int pass = 0;
+            ClassInfo[] classesToCheck = null;
+            while (pass < 5 ) {
+                switch(pass) {
+                case 0:
+                    classesToCheck = pkg.ordinaryClasses();
+                    break;
+                case 1:
+                    classesToCheck = pkg.enums();
+                    break;
+                case 2:
+                    classesToCheck = pkg.errors();
+                    break;
+                case 3:
+                    classesToCheck = pkg.exceptions();
+                    break;
+                case 4:
+                    classesToCheck = pkg.interfaces();
+                    break;
+                default:
+                    System.err.println("Error reading package: " + pkg.name());
+                    break;
+                }
+                for (ClassInfo cl : classesToCheck) {
+                    if (!cl.isHidden()) {
+                        allHidden = false;
+                        break;
+                    }
+                }
+                if (!allHidden) {
+                    break;
+                }
+                pass++;
+            }
+            if (allHidden) {
+                continue;
+            }
+
+            data.setValue("reference", "true");
+            data.setValue("docs.packages." + i + ".name", s);
+            data.setValue("docs.packages." + i + ".link", pkg.htmlPage());
+            data.setValue("docs.packages." + i + ".since", pkg.getSince());
+            TagInfo.makeHDF(data, "docs.packages." + i + ".shortDescr",
+                                               pkg.firstSentenceTags());
+            i++;
+        }
+
+        sinceTagger.writeVersionNames(data);
+        return data;
+    }
+
+    public static void writeDirectory(File dir, String relative)
+    {
+        File[] files = dir.listFiles();
+        int i, count = files.length;
+        for (i=0; i<count; i++) {
+            File f = files[i];
+            if (f.isFile()) {
+                String templ = relative + f.getName();
+                int len = templ.length();
+                if (len > 3 && ".cs".equals(templ.substring(len-3))) {
+                    HDF data = makeHDF();
+                    String filename = templ.substring(0,len-3) + htmlExtension;
+                    ClearPage.write(data, templ, filename);
+                }
+                else if (len > 3 && ".jd".equals(templ.substring(len-3))) {
+                    String filename = templ.substring(0,len-3) + htmlExtension;
+                    DocFile.writePage(f.getAbsolutePath(), relative, filename);
+                }
+                else {
+                    ClearPage.copyFile(f, templ);
+                }
+            }
+            else if (f.isDirectory()) {
+                writeDirectory(f, relative + f.getName() + "/");
+            }
+        }
+    }
+
+    public static void writeHTMLPages()
+    {
+        for (String htmlDir : ClearPage.htmlDirs) {
+            File f = new File(htmlDir);
+            if (!f.isDirectory()) {
+                System.err.println("htmlDir not a directory: " + htmlDir);
+                continue;
+            }
+            writeDirectory(f, "");
+        }
+    }
+
+    public static void writeLists()
+    {
+        HDF data = makeHDF();
+
+        ClassInfo[] classes = Converter.rootClasses();
+
+        SortedMap<String, Object> sorted = new TreeMap<String, Object>();
+        for (ClassInfo cl: classes) {
+            if (cl.isHidden()) {
+                continue;
+            }
+            sorted.put(cl.qualifiedName(), cl);
+            PackageInfo pkg = cl.containingPackage();
+            String name;
+            if (pkg == null) {
+                name = "";
+            } else {
+                name = pkg.name();
+            }
+            sorted.put(name, pkg);
+        }
+
+        int i = 0;
+        for (String s: sorted.keySet()) {
+            data.setValue("docs.pages." + i + ".id" , ""+i);
+            data.setValue("docs.pages." + i + ".label" , s);
+
+            Object o = sorted.get(s);
+            if (o instanceof PackageInfo) {
+                PackageInfo pkg = (PackageInfo)o;
+                data.setValue("docs.pages." + i + ".link" , pkg.htmlPage());
+                data.setValue("docs.pages." + i + ".type" , "package");
+            }
+            else if (o instanceof ClassInfo) {
+                ClassInfo cl = (ClassInfo)o;
+                data.setValue("docs.pages." + i + ".link" , cl.htmlPage());
+                data.setValue("docs.pages." + i + ".type" , "class");
+            }
+            i++;
+        }
+
+        ClearPage.write(data, "lists.cs", javadocDir + "lists.js");
+    }
+
+    public static void cantStripThis(ClassInfo cl, HashSet<ClassInfo> notStrippable) {
+        if (!notStrippable.add(cl)) {
+            // slight optimization: if it already contains cl, it already contains
+            // all of cl's parents
+            return;
+        }
+        ClassInfo supr = cl.superclass();
+        if (supr != null) {
+            cantStripThis(supr, notStrippable);
+        }
+        for (ClassInfo iface: cl.interfaces()) {
+            cantStripThis(iface, notStrippable);
+        }
+    }
+
+    private static String getPrintableName(ClassInfo cl) {
+        ClassInfo containingClass = cl.containingClass();
+        if (containingClass != null) {
+            // This is an inner class.
+            String baseName = cl.name();
+            baseName = baseName.substring(baseName.lastIndexOf('.') + 1);
+            return getPrintableName(containingClass) + '$' + baseName;
+        }
+        return cl.qualifiedName();
+    }
+
+    /**
+     * Writes the list of classes that must be present in order to
+     * provide the non-hidden APIs known to javadoc.
+     *
+     * @param filename the path to the file to write the list to
+     */
+    public static void writeKeepList(String filename) {
+        HashSet<ClassInfo> notStrippable = new HashSet<ClassInfo>();
+        ClassInfo[] all = Converter.allClasses();
+        Arrays.sort(all); // just to make the file a little more readable
+
+        // If a class is public and not hidden, then it and everything it derives
+        // from cannot be stripped.  Otherwise we can strip it.
+        for (ClassInfo cl: all) {
+            if (cl.isPublic() && !cl.isHidden()) {
+                cantStripThis(cl, notStrippable);
+            }
+        }
+        PrintStream stream = null;
+        try {
+            stream = new PrintStream(filename);
+            for (ClassInfo cl: notStrippable) {
+                stream.println(getPrintableName(cl));
+            }
+        }
+        catch (FileNotFoundException e) {
+            System.err.println("error writing file: " + filename);
+        }
+        finally {
+            if (stream != null) {
+                stream.close();
+            }
+        }
+    }
+
+    private static PackageInfo[] sVisiblePackages = null;
+    public static PackageInfo[] choosePackages() {
+        if (sVisiblePackages != null) {
+            return sVisiblePackages;
+        }
+
+        ClassInfo[] classes = Converter.rootClasses();
+        SortedMap<String, PackageInfo> sorted = new TreeMap<String, PackageInfo>();
+        for (ClassInfo cl: classes) {
+            PackageInfo pkg = cl.containingPackage();
+            String name;
+            if (pkg == null) {
+                name = "";
+            } else {
+                name = pkg.name();
+            }
+            sorted.put(name, pkg);
+        }
+
+        ArrayList<PackageInfo> result = new ArrayList();
+
+        for (String s: sorted.keySet()) {
+            PackageInfo pkg = sorted.get(s);
+
+            if (pkg.isHidden()) {
+                continue;
+            }
+            Boolean allHidden = true;
+            int pass = 0;
+            ClassInfo[] classesToCheck = null;
+            while (pass < 5 ) {
+                switch(pass) {
+                case 0:
+                    classesToCheck = pkg.ordinaryClasses();
+                    break;
+                case 1:
+                    classesToCheck = pkg.enums();
+                    break;
+                case 2:
+                    classesToCheck = pkg.errors();
+                    break;
+                case 3:
+                    classesToCheck = pkg.exceptions();
+                    break;
+                case 4:
+                    classesToCheck = pkg.interfaces();
+                    break;
+                default:
+                    System.err.println("Error reading package: " + pkg.name());
+                    break;
+                }
+                for (ClassInfo cl : classesToCheck) {
+                    if (!cl.isHidden()) {
+                        allHidden = false;
+                        break;
+                    }
+                }
+                if (!allHidden) {
+                    break;
+                }
+                pass++;
+            }
+            if (allHidden) {
+                continue;
+            }
+
+            result.add(pkg);
+        }
+
+        sVisiblePackages = result.toArray(new PackageInfo[result.size()]);
+        return sVisiblePackages;
+    }
+
+    public static void writePackages(String filename)
+    {
+        HDF data = makePackageHDF();
+
+        int i = 0;
+        for (PackageInfo pkg: choosePackages()) {
+            writePackage(pkg);
+
+            data.setValue("docs.packages." + i + ".name", pkg.name());
+            data.setValue("docs.packages." + i + ".link", pkg.htmlPage());
+            TagInfo.makeHDF(data, "docs.packages." + i + ".shortDescr",
+                            pkg.firstSentenceTags());
+
+            i++;
+        }
+
+        setPageTitle(data, "Package Index");
+
+        TagInfo.makeHDF(data, "root.descr",
+                Converter.convertTags(root.inlineTags(), null));
+
+        ClearPage.write(data, "packages.cs", filename);
+        ClearPage.write(data, "package-list.cs", javadocDir + "package-list");
+
+        Proofread.writePackages(filename,
+                Converter.convertTags(root.inlineTags(), null));
+    }
+
+    public static void writePackage(PackageInfo pkg)
+    {
+        // these this and the description are in the same directory,
+        // so it's okay
+        HDF data = makePackageHDF();
+
+        String name = pkg.name();
+
+        data.setValue("package.name", name);
+        data.setValue("package.since", pkg.getSince());
+        data.setValue("package.descr", "...description...");
+
+        makeClassListHDF(data, "package.interfaces",
+                         ClassInfo.sortByName(pkg.interfaces()));
+        makeClassListHDF(data, "package.classes",
+                         ClassInfo.sortByName(pkg.ordinaryClasses()));
+        makeClassListHDF(data, "package.enums",
+                         ClassInfo.sortByName(pkg.enums()));
+        makeClassListHDF(data, "package.exceptions",
+                         ClassInfo.sortByName(pkg.exceptions()));
+        makeClassListHDF(data, "package.errors",
+                         ClassInfo.sortByName(pkg.errors()));
+        TagInfo.makeHDF(data, "package.shortDescr",
+                         pkg.firstSentenceTags());
+        TagInfo.makeHDF(data, "package.descr", pkg.inlineTags());
+
+        String filename = pkg.htmlPage();
+        setPageTitle(data, name);
+        ClearPage.write(data, "package.cs", filename);
+
+        filename = pkg.fullDescriptionHtmlPage();
+        setPageTitle(data, name + " Details");
+        ClearPage.write(data, "package-descr.cs", filename);
+
+        Proofread.writePackage(filename, pkg.inlineTags());
+    }
+
+    public static void writeClassLists()
+    {
+        int i;
+        HDF data = makePackageHDF();
+
+        ClassInfo[] classes = PackageInfo.filterHidden(
+                                    Converter.convertClasses(root.classes()));
+        if (classes.length == 0) {
+            return ;
+        }
+
+        Sorter[] sorted = new Sorter[classes.length];
+        for (i=0; i<sorted.length; i++) {
+            ClassInfo cl = classes[i];
+            String name = cl.name();
+            sorted[i] = new Sorter(name, cl);
+        }
+
+        Arrays.sort(sorted);
+
+        // make a pass and resolve ones that have the same name
+        int firstMatch = 0;
+        String lastName = sorted[0].label;
+        for (i=1; i<sorted.length; i++) {
+            String s = sorted[i].label;
+            if (!lastName.equals(s)) {
+                if (firstMatch != i-1) {
+                    // there were duplicates
+                    for (int j=firstMatch; j<i; j++) {
+                        PackageInfo pkg = ((ClassInfo)sorted[j].data).containingPackage();
+                        if (pkg != null) {
+                            sorted[j].label = sorted[j].label + " (" + pkg.name() + ")";
+                        }
+                    }
+                }
+                firstMatch = i;
+                lastName = s;
+            }
+        }
+
+        // and sort again
+        Arrays.sort(sorted);
+
+        for (i=0; i<sorted.length; i++) {
+            String s = sorted[i].label;
+            ClassInfo cl = (ClassInfo)sorted[i].data;
+            char first = Character.toUpperCase(s.charAt(0));
+            cl.makeShortDescrHDF(data, "docs.classes." + first + '.' + i);
+        }
+
+        setPageTitle(data, "Class Index");
+        ClearPage.write(data, "classes.cs", javadocDir + "classes" + htmlExtension);
+    }
+
+    // we use the word keywords because "index" means something else in html land
+    // the user only ever sees the word index
+/*    public static void writeKeywords()
+    {
+        ArrayList<KeywordEntry> keywords = new ArrayList<KeywordEntry>();
+
+        ClassInfo[] classes = PackageInfo.filterHidden(Converter.convertClasses(root.classes()));
+
+        for (ClassInfo cl: classes) {
+            cl.makeKeywordEntries(keywords);
+        }
+
+        HDF data = makeHDF();
+
+        Collections.sort(keywords);
+
+        int i=0;
+        for (KeywordEntry entry: keywords) {
+            String base = "keywords." + entry.firstChar() + "." + i;
+            entry.makeHDF(data, base);
+            i++;
+        }
+
+        setPageTitle(data, "Index");
+        ClearPage.write(data, "keywords.cs", javadocDir + "keywords" + htmlExtension);
+    } */
+
+    public static void writeHierarchy()
+    {
+        ClassInfo[] classes = Converter.rootClasses();
+        ArrayList<ClassInfo> info = new ArrayList<ClassInfo>();
+        for (ClassInfo cl: classes) {
+            if (!cl.isHidden()) {
+                info.add(cl);
+            }
+        }
+        HDF data = makePackageHDF();
+        Hierarchy.makeHierarchy(data, info.toArray(new ClassInfo[info.size()]));
+        setPageTitle(data, "Class Hierarchy");
+        ClearPage.write(data, "hierarchy.cs", javadocDir + "hierarchy" + htmlExtension);
+    }
+
+    public static void writeClasses()
+    {
+        ClassInfo[] classes = Converter.rootClasses();
+
+        for (ClassInfo cl: classes) {
+            HDF data = makePackageHDF();
+            if (!cl.isHidden()) {
+                writeClass(cl, data);
+            }
+        }
+    }
+
+    public static void writeClass(ClassInfo cl, HDF data)
+    {
+        cl.makeHDF(data);
+
+        setPageTitle(data, cl.name());
+        ClearPage.write(data, "class.cs", cl.htmlPage());
+
+        Proofread.writeClass(cl.htmlPage(), cl);
+    }
+
+    public static void makeClassListHDF(HDF data, String base,
+            ClassInfo[] classes)
+    {
+        for (int i=0; i<classes.length; i++) {
+            ClassInfo cl = classes[i];
+            if (!cl.isHidden()) {
+                cl.makeShortDescrHDF(data, base + "." + i);
+            }
+        }
+    }
+
+    public static String linkTarget(String source, String target)
+    {
+        String[] src = source.split("/");
+        String[] tgt = target.split("/");
+
+        int srclen = src.length;
+        int tgtlen = tgt.length;
+
+        int same = 0;
+        while (same < (srclen-1)
+                && same < (tgtlen-1)
+                && (src[same].equals(tgt[same]))) {
+            same++;
+        }
+
+        String s = "";
+
+        int up = srclen-same-1;
+        for (int i=0; i<up; i++) {
+            s += "../";
+        }
+
+
+        int N = tgtlen-1;
+        for (int i=same; i<N; i++) {
+            s += tgt[i] + '/';
+        }
+        s += tgt[tgtlen-1];
+
+        return s;
+    }
+
+    /**
+     * Returns true if the given element has an @hide or @pending annotation.
+     */
+    private static boolean hasHideAnnotation(Doc doc) {
+        String comment = doc.getRawCommentText();
+        return comment.indexOf("@hide") != -1 || comment.indexOf("@pending") != -1;
+    }
+
+    /**
+     * Returns true if the given element is hidden.
+     */
+    private static boolean isHidden(Doc doc) {
+        // Methods, fields, constructors.
+        if (doc instanceof MemberDoc) {
+            return hasHideAnnotation(doc);
+        }
+
+        // Classes, interfaces, enums, annotation types.
+        if (doc instanceof ClassDoc) {
+            ClassDoc classDoc = (ClassDoc) doc;
+
+            // Check the containing package.
+            if (hasHideAnnotation(classDoc.containingPackage())) {
+                return true;
+            }
+
+            // Check the class doc and containing class docs if this is a
+            // nested class.
+            ClassDoc current = classDoc;
+            do {
+                if (hasHideAnnotation(current)) {
+                    return true;
+                }
+
+                current = current.containingClass();
+            } while (current != null);
+        }
+
+        return false;
+    }
+
+    /**
+     * Filters out hidden elements.
+     */
+    private static Object filterHidden(Object o, Class<?> expected) {
+        if (o == null) {
+            return null;
+        }
+
+        Class type = o.getClass();
+        if (type.getName().startsWith("com.sun.")) {
+            // TODO: Implement interfaces from superclasses, too.
+            return Proxy.newProxyInstance(type.getClassLoader(),
+                    type.getInterfaces(), new HideHandler(o));
+        } else if (o instanceof Object[]) {
+            Class<?> componentType = expected.getComponentType();
+            Object[] array = (Object[]) o;
+            List<Object> list = new ArrayList<Object>(array.length);
+            for (Object entry : array) {
+                if ((entry instanceof Doc) && isHidden((Doc) entry)) {
+                    continue;
+                }
+                list.add(filterHidden(entry, componentType));
+            }
+            return list.toArray(
+                    (Object[]) Array.newInstance(componentType, list.size()));
+        } else {
+            return o;
+        }
+    }
+
+    /**
+     * Filters hidden elements out of method return values.
+     */
+    private static class HideHandler implements InvocationHandler {
+
+        private final Object target;
+
+        public HideHandler(Object target) {
+            this.target = target;
+        }
+
+        public Object invoke(Object proxy, Method method, Object[] args)
+                throws Throwable {
+            String methodName = method.getName();
+            if (args != null) {
+                if (methodName.equals("compareTo") ||
+                    methodName.equals("equals") ||
+                    methodName.equals("overrides") ||
+                    methodName.equals("subclassOf")) {
+                    args[0] = unwrap(args[0]);
+                }
+            }
+
+            if (methodName.equals("getRawCommentText")) {
+                return filterComment((String) method.invoke(target, args));
+            }
+
+            // escape "&" in disjunctive types.
+            if (proxy instanceof Type && methodName.equals("toString")) {
+                return ((String) method.invoke(target, args))
+                        .replace("&", "&amp;");
+            }
+
+            try {
+                return filterHidden(method.invoke(target, args),
+                        method.getReturnType());
+            } catch (InvocationTargetException e) {
+                throw e.getTargetException();
+            }
+        }
+
+        private String filterComment(String s) {
+            if (s == null) {
+                return null;
+            }
+
+            s = s.trim();
+
+            // Work around off by one error
+            while (s.length() >= 5
+                    && s.charAt(s.length() - 5) == '{') {
+                s += "&nbsp;";
+            }
+
+            return s;
+        }
+
+        private static Object unwrap(Object proxy) {
+            if (proxy instanceof Proxy)
+                return ((HideHandler)Proxy.getInvocationHandler(proxy)).target;
+            return proxy;
+        }
+    }
+
+    public static String scope(Scoped scoped) {
+        if (scoped.isPublic()) {
+            return "public";
+        }
+        else if (scoped.isProtected()) {
+            return "protected";
+        }
+        else if (scoped.isPackagePrivate()) {
+            return "";
+        }
+        else if (scoped.isPrivate()) {
+            return "private";
+        }
+        else {
+            throw new RuntimeException("invalid scope for object " + scoped);
+        }
+    }
+
+    /**
+     * Collect the values used by the Dev tools and write them in files packaged with the SDK
+     * @param output the ouput directory for the files.
+     */
+    private static void writeSdkValues(String output) {
+        ArrayList<String> activityActions = new ArrayList<String>();
+        ArrayList<String> broadcastActions = new ArrayList<String>();
+        ArrayList<String> serviceActions = new ArrayList<String>();
+        ArrayList<String> categories = new ArrayList<String>();
+        ArrayList<String> features = new ArrayList<String>();
+
+        ArrayList<ClassInfo> layouts = new ArrayList<ClassInfo>();
+        ArrayList<ClassInfo> widgets = new ArrayList<ClassInfo>();
+        ArrayList<ClassInfo> layoutParams = new ArrayList<ClassInfo>();
+
+        ClassInfo[] classes = Converter.allClasses();
+
+        // Go through all the fields of all the classes, looking SDK stuff.
+        for (ClassInfo clazz : classes) {
+
+            // first check constant fields for the SdkConstant annotation.
+            FieldInfo[] fields = clazz.allSelfFields();
+            for (FieldInfo field : fields) {
+                Object cValue = field.constantValue();
+                if (cValue != null) {
+                    AnnotationInstanceInfo[] annotations = field.annotations();
+                    if (annotations.length > 0) {
+                        for (AnnotationInstanceInfo annotation : annotations) {
+                            if (SDK_CONSTANT_ANNOTATION.equals(annotation.type().qualifiedName())) {
+                                AnnotationValueInfo[] values = annotation.elementValues();
+                                if (values.length > 0) {
+                                    String type = values[0].valueString();
+                                    if (SDK_CONSTANT_TYPE_ACTIVITY_ACTION.equals(type)) {
+                                        activityActions.add(cValue.toString());
+                                    } else if (SDK_CONSTANT_TYPE_BROADCAST_ACTION.equals(type)) {
+                                        broadcastActions.add(cValue.toString());
+                                    } else if (SDK_CONSTANT_TYPE_SERVICE_ACTION.equals(type)) {
+                                        serviceActions.add(cValue.toString());
+                                    } else if (SDK_CONSTANT_TYPE_CATEGORY.equals(type)) {
+                                        categories.add(cValue.toString());
+                                    } else if (SDK_CONSTANT_TYPE_FEATURE.equals(type)) {
+                                        features.add(cValue.toString());
+                                    }
+                                }
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+
+            // Now check the class for @Widget or if its in the android.widget package
+            // (unless the class is hidden or abstract, or non public)
+            if (clazz.isHidden() == false && clazz.isPublic() && clazz.isAbstract() == false) {
+                boolean annotated = false;
+                AnnotationInstanceInfo[] annotations = clazz.annotations();
+                if (annotations.length > 0) {
+                    for (AnnotationInstanceInfo annotation : annotations) {
+                        if (SDK_WIDGET_ANNOTATION.equals(annotation.type().qualifiedName())) {
+                            widgets.add(clazz);
+                            annotated = true;
+                            break;
+                        } else if (SDK_LAYOUT_ANNOTATION.equals(annotation.type().qualifiedName())) {
+                            layouts.add(clazz);
+                            annotated = true;
+                            break;
+                        }
+                    }
+                }
+
+                if (annotated == false) {
+                    // lets check if this is inside android.widget
+                    PackageInfo pckg = clazz.containingPackage();
+                    String packageName = pckg.name();
+                    if ("android.widget".equals(packageName) ||
+                            "android.view".equals(packageName)) {
+                        // now we check what this class inherits either from android.view.ViewGroup
+                        // or android.view.View, or android.view.ViewGroup.LayoutParams
+                        int type = checkInheritance(clazz);
+                        switch (type) {
+                            case TYPE_WIDGET:
+                                widgets.add(clazz);
+                                break;
+                            case TYPE_LAYOUT:
+                                layouts.add(clazz);
+                                break;
+                            case TYPE_LAYOUT_PARAM:
+                                layoutParams.add(clazz);
+                                break;
+                        }
+                    }
+                }
+            }
+        }
+
+        // now write the files, whether or not the list are empty.
+        // the SDK built requires those files to be present.
+
+        Collections.sort(activityActions);
+        writeValues(output + "/activity_actions.txt", activityActions);
+
+        Collections.sort(broadcastActions);
+        writeValues(output + "/broadcast_actions.txt", broadcastActions);
+
+        Collections.sort(serviceActions);
+        writeValues(output + "/service_actions.txt", serviceActions);
+
+        Collections.sort(categories);
+        writeValues(output + "/categories.txt", categories);
+
+        Collections.sort(features);
+        writeValues(output + "/features.txt", features);
+
+        // before writing the list of classes, we do some checks, to make sure the layout params
+        // are enclosed by a layout class (and not one that has been declared as a widget)
+        for (int i = 0 ; i < layoutParams.size();) {
+            ClassInfo layoutParamClass = layoutParams.get(i);
+            ClassInfo containingClass = layoutParamClass.containingClass();
+            if (containingClass == null || layouts.indexOf(containingClass) == -1) {
+                layoutParams.remove(i);
+            } else {
+                i++;
+            }
+        }
+
+        writeClasses(output + "/widgets.txt", widgets, layouts, layoutParams);
+    }
+
+    /**
+     * Writes a list of values into a text files.
+     * @param pathname the absolute os path of the output file.
+     * @param values the list of values to write.
+     */
+    private static void writeValues(String pathname, ArrayList<String> values) {
+        FileWriter fw = null;
+        BufferedWriter bw = null;
+        try {
+            fw = new FileWriter(pathname, false);
+            bw = new BufferedWriter(fw);
+
+            for (String value : values) {
+                bw.append(value).append('\n');
+            }
+        } catch (IOException e) {
+            // pass for now
+        } finally {
+            try {
+                if (bw != null) bw.close();
+            } catch (IOException e) {
+                // pass for now
+            }
+            try {
+                if (fw != null) fw.close();
+            } catch (IOException e) {
+                // pass for now
+            }
+        }
+    }
+
+    /**
+     * Writes the widget/layout/layout param classes into a text files.
+     * @param pathname the absolute os path of the output file.
+     * @param widgets the list of widget classes to write.
+     * @param layouts the list of layout classes to write.
+     * @param layoutParams the list of layout param classes to write.
+     */
+    private static void writeClasses(String pathname, ArrayList<ClassInfo> widgets,
+            ArrayList<ClassInfo> layouts, ArrayList<ClassInfo> layoutParams) {
+        FileWriter fw = null;
+        BufferedWriter bw = null;
+        try {
+            fw = new FileWriter(pathname, false);
+            bw = new BufferedWriter(fw);
+
+            // write the 3 types of classes.
+            for (ClassInfo clazz : widgets) {
+                writeClass(bw, clazz, 'W');
+            }
+            for (ClassInfo clazz : layoutParams) {
+                writeClass(bw, clazz, 'P');
+            }
+            for (ClassInfo clazz : layouts) {
+                writeClass(bw, clazz, 'L');
+            }
+        } catch (IOException e) {
+            // pass for now
+        } finally {
+            try {
+                if (bw != null) bw.close();
+            } catch (IOException e) {
+                // pass for now
+            }
+            try {
+                if (fw != null) fw.close();
+            } catch (IOException e) {
+                // pass for now
+            }
+        }
+    }
+
+    /**
+     * Writes a class name and its super class names into a {@link BufferedWriter}.
+     * @param writer the BufferedWriter to write into
+     * @param clazz the class to write
+     * @param prefix the prefix to put at the beginning of the line.
+     * @throws IOException
+     */
+    private static void writeClass(BufferedWriter writer, ClassInfo clazz, char prefix)
+            throws IOException {
+        writer.append(prefix).append(clazz.qualifiedName());
+        ClassInfo superClass = clazz;
+        while ((superClass = superClass.superclass()) != null) {
+            writer.append(' ').append(superClass.qualifiedName());
+        }
+        writer.append('\n');
+    }
+
+    /**
+     * Checks the inheritance of {@link ClassInfo} objects. This method return
+     * <ul>
+     * <li>{@link #TYPE_LAYOUT}: if the class extends <code>android.view.ViewGroup</code></li>
+     * <li>{@link #TYPE_WIDGET}: if the class extends <code>android.view.View</code></li>
+     * <li>{@link #TYPE_LAYOUT_PARAM}: if the class extends <code>android.view.ViewGroup$LayoutParams</code></li>
+     * <li>{@link #TYPE_NONE}: in all other cases</li>
+     * </ul>
+     * @param clazz the {@link ClassInfo} to check.
+     */
+    private static int checkInheritance(ClassInfo clazz) {
+        if ("android.view.ViewGroup".equals(clazz.qualifiedName())) {
+            return TYPE_LAYOUT;
+        } else if ("android.view.View".equals(clazz.qualifiedName())) {
+            return TYPE_WIDGET;
+        } else if ("android.view.ViewGroup.LayoutParams".equals(clazz.qualifiedName())) {
+            return TYPE_LAYOUT_PARAM;
+        }
+
+        ClassInfo parent = clazz.superclass();
+        if (parent != null) {
+            return checkInheritance(parent);
+        }
+
+        return TYPE_NONE;
+    }
+}
diff --git a/build/tools/droiddoc/src/Errors.java b/build/tools/droiddoc/src/Errors.java
new file mode 100644 (file)
index 0000000..0a91abc
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+public class Errors
+{
+    public static boolean hadError = false;
+    private static boolean warningsAreErrors = false;
+    private static TreeSet<Message> allErrors = new TreeSet<Message>();
+
+    private static class Message implements Comparable {
+        SourcePositionInfo pos;
+        int level;
+        String msg;
+
+        Message(SourcePositionInfo p, int l, String m) {
+            pos = p;
+            level = l;
+            msg = m;
+        }
+
+        public int compareTo(Object o) {
+            Message that = (Message)o;
+            int r = this.pos.compareTo(that.pos);
+            if (r != 0) return r;
+            return this.msg.compareTo(that.msg);
+        }
+
+        @Override
+        public String toString() {
+            String whereText = this.pos == null ? "unknown: " : this.pos.toString() + ':';
+            return whereText + this.msg;
+        }
+    }
+
+    public static void error(Error error, SourcePositionInfo where, String text) {
+        if (error.level == HIDDEN) {
+            return;
+        }
+
+        int level = (!warningsAreErrors && error.level == WARNING) ? WARNING : ERROR;
+        String which = level == WARNING ? " warning " : " error ";
+        String message = which + error.code + ": " + text;
+
+        if (where == null) {
+            where = new SourcePositionInfo("unknown", 0, 0);
+        }
+
+        allErrors.add(new Message(where, level, message));
+
+        if (error.level == ERROR || (warningsAreErrors && error.level == WARNING)) {
+            hadError = true;
+        }
+    }
+
+    public static void printErrors() {
+        for (Message m: allErrors) {
+            if (m.level == WARNING) {
+                System.err.println(m.toString());
+            }
+        }
+        for (Message m: allErrors) {
+            if (m.level == ERROR) {
+                System.err.println(m.toString());
+            }
+        }
+    }
+
+    public static int HIDDEN = 0;
+    public static int WARNING = 1;
+    public static int ERROR = 2;
+
+    public static void setWarningsAreErrors(boolean val) {
+        warningsAreErrors = val;
+    }
+
+    public static class Error {
+        public int code;
+        public int level;
+
+        public Error(int code, int level)
+        {
+            this.code = code;
+            this.level = level;
+        }
+    }
+
+    public static Error UNRESOLVED_LINK = new Error(1, WARNING);
+    public static Error BAD_INCLUDE_TAG = new Error(2, WARNING);
+    public static Error UNKNOWN_TAG = new Error(3, WARNING);
+    public static Error UNKNOWN_PARAM_TAG_NAME = new Error(4, WARNING);
+    public static Error UNDOCUMENTED_PARAMETER = new Error(5, HIDDEN);
+    public static Error BAD_ATTR_TAG = new Error(6, ERROR);
+    public static Error BAD_INHERITDOC = new Error(7, HIDDEN);
+    public static Error HIDDEN_LINK = new Error(8, WARNING);
+    public static Error HIDDEN_CONSTRUCTOR = new Error(9, WARNING);
+    public static Error UNAVAILABLE_SYMBOL = new Error(10, ERROR);
+    public static Error HIDDEN_SUPERCLASS = new Error(11, WARNING);
+    public static Error DEPRECATED = new Error(12, HIDDEN);
+    public static Error DEPRECATION_MISMATCH = new Error(13, WARNING);
+    public static Error MISSING_COMMENT = new Error(14, WARNING);
+    public static Error IO_ERROR = new Error(15, HIDDEN);
+    public static Error NO_SINCE_DATA = new Error(16, HIDDEN);
+
+    public static Error[] ERRORS = {
+            UNRESOLVED_LINK,
+            BAD_INCLUDE_TAG,
+            UNKNOWN_TAG,
+            UNKNOWN_PARAM_TAG_NAME,
+            UNDOCUMENTED_PARAMETER,
+            BAD_ATTR_TAG,
+            BAD_INHERITDOC,
+            HIDDEN_LINK,
+            HIDDEN_CONSTRUCTOR,
+            UNAVAILABLE_SYMBOL,
+            HIDDEN_SUPERCLASS,
+            DEPRECATED,
+            DEPRECATION_MISMATCH,
+            MISSING_COMMENT,
+            IO_ERROR,
+            NO_SINCE_DATA,
+        };
+
+    public static boolean setErrorLevel(int code, int level) {
+        for (Error e: ERRORS) {
+            if (e.code == code) {
+                e.level = level;
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/build/tools/droiddoc/src/FieldInfo.java b/build/tools/droiddoc/src/FieldInfo.java
new file mode 100644 (file)
index 0000000..d9371e8
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+
+import java.util.Comparator;
+
+public class FieldInfo extends MemberInfo
+{
+    public static final Comparator<FieldInfo> comparator = new Comparator<FieldInfo>() {
+        public int compare(FieldInfo a, FieldInfo b) {
+            return a.name().compareTo(b.name());
+        }
+    };
+
+    public FieldInfo(String name, ClassInfo containingClass, ClassInfo realContainingClass,
+                        boolean isPublic, boolean isProtected,
+                        boolean isPackagePrivate, boolean isPrivate,
+                        boolean isFinal, boolean isStatic, boolean isTransient, boolean isVolatile,
+                        boolean isSynthetic, TypeInfo type, String rawCommentText,
+                        Object constantValue,
+                        SourcePositionInfo position,
+                        AnnotationInstanceInfo[] annotations)
+    {
+        super(rawCommentText, name, null, containingClass, realContainingClass,
+                isPublic, isProtected, isPackagePrivate, isPrivate,
+                isFinal, isStatic, isSynthetic, chooseKind(isFinal, isStatic), position,
+                annotations);
+        mIsTransient = isTransient;
+        mIsVolatile = isVolatile;
+        mType = type;
+        mConstantValue = constantValue;
+    }
+
+    public FieldInfo cloneForClass(ClassInfo newContainingClass) {
+        return new FieldInfo(name(), newContainingClass, realContainingClass(),
+                isPublic(), isProtected(), isPackagePrivate(),
+                isPrivate(), isFinal(), isStatic(), isTransient(), isVolatile(),
+                isSynthetic(), mType, getRawCommentText(), mConstantValue, position(),
+                annotations());
+    }
+
+    static String chooseKind(boolean isFinal, boolean isStatic)
+    {
+        if (isStatic && isFinal) {
+            return "constant";
+        } else {
+            return "field";
+        }
+    }
+
+    public TypeInfo type()
+    {
+        return mType;
+    }
+
+    public boolean isConstant()
+    {
+        return isStatic() && isFinal();
+    }
+
+    public TagInfo[] firstSentenceTags()
+    {
+        return comment().briefTags();
+    }
+
+    public TagInfo[] inlineTags()
+    {
+        return comment().tags();
+    }
+
+    public Object constantValue()
+    {
+        return mConstantValue;
+    }
+
+    public String constantLiteralValue()
+    {
+        return constantLiteralValue(mConstantValue);
+    }
+
+    public boolean isDeprecated() {
+        boolean deprecated = false;
+        if (!mDeprecatedKnown) {
+            boolean commentDeprecated = (comment().deprecatedTags().length > 0);
+            boolean annotationDeprecated = false;
+            for (AnnotationInstanceInfo annotation : annotations()) {
+                if (annotation.type().qualifiedName().equals("java.lang.Deprecated")) {
+                    annotationDeprecated = true;
+                    break;
+                }
+            }
+
+            if (commentDeprecated != annotationDeprecated) {
+                Errors.error(Errors.DEPRECATION_MISMATCH, position(),
+                        "Field " + mContainingClass.qualifiedName() + "." + name()
+                        + ": @Deprecated annotation and @deprecated comment do not match");
+            }
+
+            mIsDeprecated = commentDeprecated | annotationDeprecated;
+            mDeprecatedKnown = true;
+        }
+        return mIsDeprecated;
+    }
+
+    public static String constantLiteralValue(Object val)
+    {
+        String str = null;
+        if (val != null) {
+            if (val instanceof Boolean
+                    || val instanceof Byte
+                    || val instanceof Short
+                    || val instanceof Integer)
+            {
+                str = val.toString();
+            }
+            //catch all special values
+            else if (val instanceof Double){
+                Double dbl = (Double) val;
+                    if (dbl.toString().equals("Infinity")){
+                        str = "(1.0 / 0.0)";
+                    } else if (dbl.toString().equals("-Infinity")) {
+                        str = "(-1.0 / 0.0)";
+                    } else if (dbl.isNaN()) {
+                        str = "(0.0 / 0.0)";
+                    } else {
+                        str = dbl.toString();
+                    }
+            }
+            else if (val instanceof Long) {
+                str = val.toString() + "L";
+            }
+            else if (val instanceof Float) {
+                Float fl = (Float) val;
+                if (fl.toString().equals("Infinity")) {
+                    str = "(1.0f / 0.0f)";
+                } else if (fl.toString().equals("-Infinity")) {
+                    str = "(-1.0f / 0.0f)";
+                } else if (fl.isNaN()) {
+                    str = "(0.0f / 0.0f)";
+                } else {
+                    str = val.toString() + "f";
+                }
+            }
+            else if (val instanceof Character) {
+                str = String.format("\'\\u%04x\'", val);
+            }
+            else if (val instanceof String) {
+                str = "\"" + javaEscapeString((String)val) + "\"";
+            }
+            else {
+                str = "<<<<" +val.toString() + ">>>>";
+            }
+        }
+        if (str == null) {
+            str = "null";
+        }
+        return str;
+    }
+
+    public static String javaEscapeString(String str) {
+        String result = "";
+        final int N = str.length();
+        for (int i=0; i<N; i++) {
+            char c = str.charAt(i);
+            if (c == '\\') {
+                result += "\\\\";
+            }
+            else if (c == '\t') {
+                result += "\\t";
+            }
+            else if (c == '\b') {
+                result += "\\b";
+            }
+            else if (c == '\r') {
+                result += "\\r";
+            }
+            else if (c == '\n') {
+                result += "\\n";
+            }
+            else if (c == '\f') {
+                result += "\\f";
+            }
+            else if (c == '\'') {
+                result += "\\'";
+            }
+            else if (c == '\"') {
+                result += "\\\"";
+            }
+            else if (c >= ' ' && c <= '~') {
+                result += c;
+            }
+            else {
+                result += String.format("\\u%04x", new Integer((int)c));
+            }
+        }
+        return result;
+    }
+
+
+    public void makeHDF(HDF data, String base)
+    {
+        data.setValue(base + ".kind", kind());
+        type().makeHDF(data, base + ".type");
+        data.setValue(base + ".name", name());
+        data.setValue(base + ".href", htmlPage());
+        data.setValue(base + ".anchor", anchor());
+        TagInfo.makeHDF(data, base + ".shortDescr", firstSentenceTags());
+        TagInfo.makeHDF(data, base + ".descr", inlineTags());
+        TagInfo.makeHDF(data, base + ".deprecated", comment().deprecatedTags());
+        TagInfo.makeHDF(data, base + ".seeAlso", comment().seeTags());
+        data.setValue(base + ".since", getSince());
+        data.setValue(base + ".final", isFinal() ? "final" : "");
+        data.setValue(base + ".static", isStatic() ? "static" : "");
+        if (isPublic()) {
+            data.setValue(base + ".scope", "public");
+        }
+        else if (isProtected()) {
+            data.setValue(base + ".scope", "protected");
+        }
+        else if (isPackagePrivate()) {
+            data.setValue(base + ".scope", "");
+        }
+        else if (isPrivate()) {
+            data.setValue(base + ".scope", "private");
+        }
+        Object val = mConstantValue;
+        if (val != null) {
+            String dec = null;
+            String hex = null;
+            String str = null;
+
+            if (val instanceof Boolean) {
+                str = ((Boolean)val).toString();
+            }
+            else if (val instanceof Byte) {
+                dec = String.format("%d", val);
+                hex = String.format("0x%02x", val);
+            }
+            else if (val instanceof Character) {
+                dec = String.format("\'%c\'", val);
+                hex = String.format("0x%04x", val);
+            }
+            else if (val instanceof Double) {
+                str = ((Double)val).toString();
+            }
+            else if (val instanceof Float) {
+                str = ((Float)val).toString();
+            }
+            else if (val instanceof Integer) {
+                dec = String.format("%d", val);
+                hex = String.format("0x%08x", val);
+            }
+            else if (val instanceof Long) {
+                dec = String.format("%d", val);
+                hex = String.format("0x%016x", val);
+            }
+            else if (val instanceof Short) {
+                dec = String.format("%d", val);
+                hex = String.format("0x%04x", val);
+            }
+            else if (val instanceof String) {
+                str = "\"" + ((String)val) + "\"";
+            }
+            else {
+                str = "";
+            }
+
+            if (dec != null && hex != null) {
+                data.setValue(base + ".constantValue.dec", DroidDoc.escape(dec));
+                data.setValue(base + ".constantValue.hex", DroidDoc.escape(hex));
+            }
+            else {
+                data.setValue(base + ".constantValue.str", DroidDoc.escape(str));
+                data.setValue(base + ".constantValue.isString", "1");
+            }
+        }
+    }
+
+    @Override
+    public boolean isExecutable()
+    {
+        return false;
+    }
+
+    public boolean isTransient()
+    {
+        return mIsTransient;
+    }
+
+    public boolean isVolatile()
+    {
+        return mIsVolatile;
+    }
+
+    boolean mIsTransient;
+    boolean mIsVolatile;
+    boolean mDeprecatedKnown;
+    boolean mIsDeprecated;
+    TypeInfo mType;
+    Object mConstantValue;
+}
+
diff --git a/build/tools/droiddoc/src/Hierarchy.java b/build/tools/droiddoc/src/Hierarchy.java
new file mode 100644 (file)
index 0000000..ac5e1dc
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.HashMap;
+import java.util.TreeSet;
+import java.util.Set;
+import org.clearsilver.HDF;
+
+public class Hierarchy
+{
+    public static void makeHierarchy(HDF hdf, ClassInfo[] classes)
+    {
+        HashMap<String,TreeSet<String>> nodes
+                                    = new HashMap<String,TreeSet<String>>();
+
+        for (ClassInfo cl: classes) {
+            String name = cl.qualifiedName();
+
+            TreeSet<String> me = nodes.get(name);
+            if (me == null) {
+                me = new TreeSet<String>();
+                nodes.put(name, me);
+            }
+
+            ClassInfo superclass = cl.superclass();
+            String sname = superclass != null
+                                    ? superclass.qualifiedName() : null;
+            if (sname != null) {
+                TreeSet<String> s = nodes.get(sname);
+                if (s == null) {
+                    s = new TreeSet<String>();
+                    nodes.put(sname, s);
+                }
+                s.add(name);
+            }
+        }
+
+        /*
+        Set<String> keys = nodes.keySet();
+        for (String n: keys) {
+            System.out.println("class: " + n);
+
+            TreeSet<String> values = nodes.get(n);
+            for (String v: values) {
+                System.out.println("       - " + v);
+            }
+        }
+        */
+
+        int depth = depth(nodes, "java.lang.Object");
+
+        hdf.setValue("classes.0", "");
+        hdf.setValue("colspan", "" + depth);
+
+        recurse(nodes, "java.lang.Object", hdf.getObj("classes.0"),depth,depth);
+
+        if (false) {
+            Set<String> keys = nodes.keySet();
+            if (keys.size() > 0) {
+                System.err.println("The following classes are hidden but"
+                        + " are superclasses of not-hidden classes");
+                for (String n: keys) {
+                    System.err.println("  " + n);
+                }
+            }
+        }
+    }
+
+    private static int depth(HashMap<String,TreeSet<String>> nodes,
+                                String name)
+    {
+        int d = 0;
+        TreeSet<String> derived = nodes.get(name);
+        if (derived != null && derived.size() > 0) {
+            for (String s: derived) {
+                int n = depth(nodes, s);
+                if (n > d) {
+                    d = n;
+                }
+            }
+        }
+        return d + 1;
+    }
+
+    private static boolean exists(ClassInfo cl)
+    {
+        return cl != null && !cl.isHidden() && cl.isIncluded();
+    }
+
+    private static void recurse(HashMap<String,TreeSet<String>> nodes,
+                                String name, HDF hdf, 
+                                int totalDepth, int remainingDepth)
+    {
+        int i;
+
+        hdf.setValue("indent", "" + (totalDepth-remainingDepth-1));
+        hdf.setValue("colspan", "" + remainingDepth);
+
+        ClassInfo cl = Converter.obtainClass(name);
+
+        hdf.setValue("class.label", cl.name());
+        hdf.setValue("class.qualified", cl.qualifiedName());
+        if (cl.checkLevel()) {
+            hdf.setValue("class.link", cl.htmlPage());
+        }
+
+        if (exists(cl)) {
+            hdf.setValue("exists", "1");
+        }
+
+        i = 0;
+        for (ClassInfo iface: cl.interfaces()) {
+            hdf.setValue("interfaces." + i + ".class.label", iface.name());
+            hdf.setValue("interfaces." + i + ".class.qualified", iface.qualifiedName());
+            if (iface.checkLevel()) {
+                hdf.setValue("interfaces." + i + ".class.link", iface.htmlPage());
+            }
+            if (exists(cl)) {
+                hdf.setValue("interfaces." + i + ".exists", "1");
+            }
+            i++;
+        }
+
+        TreeSet<String> derived = nodes.get(name);
+        if (derived != null && derived.size() > 0) {
+            hdf.setValue("derived", "");
+            HDF children = hdf.getObj("derived");
+            i = 0;
+            remainingDepth--;
+            for (String s: derived) {
+                String index = "" + i;
+                children.setValue(index, "");
+                recurse(nodes, s, children.getObj(index), totalDepth,
+                        remainingDepth);
+                i++;
+            }
+        }
+
+        nodes.remove(name);
+    }
+}
+
diff --git a/build/tools/droiddoc/src/InheritedTags.java b/build/tools/droiddoc/src/InheritedTags.java
new file mode 100644 (file)
index 0000000..242170c
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+import java.util.*;
+import java.io.*;
+
+public interface InheritedTags
+{
+    TagInfo[] tags();
+    InheritedTags inherited();
+}
+
diff --git a/build/tools/droiddoc/src/KeywordEntry.java b/build/tools/droiddoc/src/KeywordEntry.java
new file mode 100644 (file)
index 0000000..7e5e357
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+
+class KeywordEntry implements Comparable
+{
+    KeywordEntry(String label, String href, String comment)
+    {
+        this.label = label;
+        this.href = href;
+        this.comment = comment;
+    }
+
+    public void makeHDF(HDF data, String base)
+    {
+        data.setValue(base + ".label", this.label);
+        data.setValue(base + ".href", this.href);
+        data.setValue(base + ".comment", this.comment);
+    }
+
+    public char firstChar()
+    {
+        return Character.toUpperCase(this.label.charAt(0));
+    }
+
+    public int compareTo(Object that)
+    {
+        return this.label.compareToIgnoreCase(((KeywordEntry)that).label);
+    }
+
+    private String label;
+    private String href;
+    private String comment;
+}
+
+
diff --git a/build/tools/droiddoc/src/LinkReference.java b/build/tools/droiddoc/src/LinkReference.java
new file mode 100644 (file)
index 0000000..b1f998a
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.ArrayList;
+
+/**
+ * Class that represents what you see in an link or see tag.  This is
+ * factored out of SeeTagInfo so it can be used elsewhere (like AttrTagInfo).
+ */
+public class LinkReference {
+
+    /** The original text. */
+    public String text;
+    
+    /** The kind of this tag, if we have a new suggestion after parsing. */
+    public String kind;
+
+    /** The user visible text. */
+    public String label;
+
+    /** The link. */
+    public String href;
+
+    /** The {@link PackageInfo} if any. */
+    public PackageInfo packageInfo;
+
+    /** The {@link ClassInfo} if any. */
+    public ClassInfo classInfo;
+
+    /** The {@link MemberInfo} if any. */
+    public MemberInfo memberInfo;
+
+    /** The name of the referenced member PackageInfo} if any. */
+    public String referencedMemberName;
+
+    /** Set to true if everything is a-ok */
+    public boolean good;
+
+    /**
+     * regex pattern to use when matching explicit "<a href" reference text
+     */
+    private static final Pattern HREF_PATTERN
+            = Pattern.compile("^<a href=\"([^\"]*)\">([^<]*)</a>[ \n\r\t]*$",
+                              Pattern.CASE_INSENSITIVE);
+
+    /**
+     * regex pattern to use when matching double-quoted reference text
+     */
+    private static final Pattern QUOTE_PATTERN
+            = Pattern.compile("^\"([^\"]*)\"[ \n\r\t]*$");
+
+    /**
+     * Parse and resolve a link string.
+     *
+     * @param text the original text
+     * @param base the class or whatever that this link is on
+     * @param pos the original position in the source document
+     * @return a new link reference.  It always returns something.  If there was an
+     *         error, it logs it and fills in href and label with error text.
+     */
+    public static LinkReference parse(String text, ContainerInfo base, SourcePositionInfo pos,
+                                        boolean printOnErrors) {
+        LinkReference result = new LinkReference();
+        result.text = text;
+
+        int index;
+        int len = text.length();
+        int pairs = 0;
+        int pound = -1;
+        // split the string
+        done: {
+            for (index=0; index<len; index++) {
+                char c = text.charAt(index);
+                switch (c)
+                {
+                    case '(':
+                        pairs++;
+                        break;
+                    case '[':
+                        pairs++;
+                        break;
+                    case ')':
+                        pairs--;
+                        break;
+                    case ']':
+                        pairs--;
+                        break;
+                    case ' ':
+                    case '\t':
+                    case '\r':
+                    case '\n':
+                        if (pairs == 0) {
+                            break done;
+                        }
+                        break;
+                    case '#':
+                        if (pound < 0) {
+                            pound = index;
+                        }
+                        break;
+                }
+            }
+        }
+        if (index == len && pairs != 0) {
+            Errors.error(Errors.UNRESOLVED_LINK, pos,
+                        "unable to parse link/see tag: " + text.trim());
+            return result;
+        }
+
+        int linkend = index;
+
+        for (; index<len; index++) {
+            char c = text.charAt(index);
+            if (!(c == ' ' || c == '\t' || c == '\r' || c == '\n')) {
+                break;
+            }
+        }
+
+        result.label = text.substring(index);
+
+        String ref;
+        String mem;
+        if (pound == 0) {
+            ref = null;
+            mem = text.substring(1, linkend);
+        }
+        else if (pound > 0) {
+            ref = text.substring(0, pound);
+            mem = text.substring(pound+1, linkend);
+        }
+        else {
+            ref = text.substring(0, linkend);
+            mem = null;
+        }
+
+        // parse parameters, if any
+        String[] params = null;
+        String[] paramDimensions = null;
+        if (mem != null) {
+            index = mem.indexOf('(');
+            if (index > 0) {
+                ArrayList<String> paramList = new ArrayList<String>();
+                ArrayList<String> paramDimensionList = new ArrayList<String>();
+                len = mem.length();
+                int start = index+1;
+                final int START = 0;
+                final int TYPE = 1;
+                final int NAME = 2;
+                int dimension = 0;
+                int arraypair = 0;
+                int state = START;
+                int typestart = 0;
+                int typeend = -1;
+                for (int i=start; i<len; i++) {
+                    char c = mem.charAt(i);
+                    switch (state)
+                    {
+                        case START:
+                            if (c!=' ' && c!='\t' && c!='\r' && c!='\n') {
+                                state = TYPE;
+                                typestart = i;
+                            }
+                            break;
+                        case TYPE:
+                            if (c == '[') {
+                                if (typeend < 0) {
+                                    typeend = i;
+                                }
+                                dimension++;
+                                arraypair++;
+                            }
+                            else if (c == ']') {
+                                arraypair--;
+                            }
+                            else if (c==' ' || c=='\t' || c=='\r' || c=='\n') {
+                                if (typeend < 0) {
+                                    typeend = i;
+                                }
+                            }
+                            else {
+                                if (typeend >= 0 || c == ')' || c == ',') {
+                                    if (typeend < 0) {
+                                        typeend = i;
+                                    }
+                                    String s = mem.substring(typestart, typeend);
+                                    paramList.add(s);
+                                    s = "";
+                                    for (int j=0; j<dimension; j++) {
+                                        s += "[]";
+                                    }
+                                    paramDimensionList.add(s);
+                                    state = START;
+                                    typeend = -1;
+                                    dimension = 0;
+                                    if (c == ',' || c == ')') {
+                                        state = START;
+                                    } else {
+                                        state = NAME;
+                                    }
+                                }
+                            }
+                            break;
+                        case NAME:
+                            if (c == ',' || c == ')') {
+                                state = START;
+                            }
+                            break;
+                    }
+
+                }
+                params = paramList.toArray(new String[paramList.size()]);
+                paramDimensions = paramDimensionList.toArray(new String[paramList.size()]);
+                mem = mem.substring(0, index);
+            }
+        }
+
+        ClassInfo cl = null;
+        if (base instanceof ClassInfo) {
+            cl = (ClassInfo)base;
+        }
+
+        if (ref == null) {
+            // no class or package was provided, assume it's this class
+            if (cl != null) {
+                result.classInfo = cl;
+            }
+        } else {
+            // they provided something, maybe it's a class or a package
+            if (cl != null) {
+                result.classInfo = cl.extendedFindClass(ref);
+                if (result.classInfo == null) {
+                    result.classInfo = cl.findClass(ref);
+                }
+                if (result.classInfo == null) {
+                    result.classInfo = cl.findInnerClass(ref);
+                }
+            }
+            if (result.classInfo == null) {
+                result.classInfo = Converter.obtainClass(ref);
+            }
+            if (result.classInfo == null) {
+                result.packageInfo = Converter.obtainPackage(ref);
+            }
+        }
+
+        if (result.classInfo != null && mem != null) {
+            // it's either a field or a method, prefer a field
+            if (params == null) {
+                FieldInfo field = result.classInfo.findField(mem);
+                // findField looks in containing classes, so it might actually
+                // be somewhere else; link to where it really is, not what they
+                // typed.
+                if (field != null) {
+                    result.classInfo = field.containingClass();
+                    result.memberInfo = field;
+                }
+            }
+            if (result.memberInfo == null) {
+                MethodInfo method = result.classInfo.findMethod(mem, params, paramDimensions);
+                if (method != null) {
+                    result.classInfo = method.containingClass();
+                    result.memberInfo = method;
+                }
+            }
+        }
+
+        result.referencedMemberName = mem;
+        if (params != null) {
+            result.referencedMemberName = result.referencedMemberName + '(';
+            len = params.length;
+            if (len > 0) {
+                len--;
+                for (int i=0; i<len; i++) {
+                    result.referencedMemberName = result.referencedMemberName + params[i]
+                            + paramDimensions[i] + ", ";
+                }
+                result.referencedMemberName = result.referencedMemberName + params[len]
+                        + paramDimensions[len];
+            }
+            result.referencedMemberName = result.referencedMemberName + ")";
+        }
+
+        // debugging spew
+        if (false) {
+            result.label = result.label + "/" + ref + "/" + mem + '/';
+            if (params != null) {
+                for (int i=0; i<params.length; i++) {
+                    result.label += params[i] + "|";
+                }
+            }
+
+            FieldInfo f = (result.memberInfo instanceof FieldInfo)
+                        ? (FieldInfo)result.memberInfo
+                        : null;
+            MethodInfo m = (result.memberInfo instanceof MethodInfo)
+                        ? (MethodInfo)result.memberInfo
+                        : null;
+            result.label = result.label
+                        + "/package=" + (result.packageInfo!=null?result.packageInfo.name():"")
+                        + "/class=" + (result.classInfo!=null?result.classInfo.qualifiedName():"")
+                        + "/field=" + (f!=null?f.name():"")
+                        + "/method=" + (m!=null?m.name():"");
+            
+        }
+
+        MethodInfo method = null;
+        boolean skipHref = false;
+
+        if (result.memberInfo != null && result.memberInfo.isExecutable()) {
+           method = (MethodInfo)result.memberInfo;
+        }
+
+        if (text.startsWith("\"")) {
+            // literal quoted reference (e.g., a book title)
+            Matcher matcher = QUOTE_PATTERN.matcher(text);
+            if (! matcher.matches()) {
+                Errors.error(Errors.UNRESOLVED_LINK, pos,
+                        "unbalanced quoted link/see tag: " + text.trim());
+                result.makeError();
+                return result;
+            }
+            skipHref = true;
+            result.label = matcher.group(1);
+            result.kind = "@seeJustLabel";
+        }
+        else if (text.startsWith("<")) {
+            // explicit "<a href" form
+            Matcher matcher = HREF_PATTERN.matcher(text);
+            if (! matcher.matches()) {
+                Errors.error(Errors.UNRESOLVED_LINK, pos,
+                        "invalid <a> link/see tag: " + text.trim());
+                result.makeError();
+                return result;
+            }
+            result.href = matcher.group(1);
+            result.label = matcher.group(2);
+            result.kind = "@seeHref";
+        }
+        else if (result.packageInfo != null) {
+            result.href = result.packageInfo.htmlPage();
+            if (result.label.length() == 0) {
+                result.href = result.packageInfo.htmlPage();
+                result.label = result.packageInfo.name();
+            }
+        }
+        else if (result.classInfo != null && result.referencedMemberName == null) {
+            // class reference
+            if (result.label.length() == 0) {
+                result.label = result.classInfo.name();
+            }
+            result.href = result.classInfo.htmlPage();
+        }
+        else if (result.memberInfo != null) {
+            // member reference
+            ClassInfo containing = result.memberInfo.containingClass();
+            if (result.memberInfo.isExecutable()) {
+                if (result.referencedMemberName.indexOf('(') < 0) {
+                    result.referencedMemberName += method.flatSignature();
+                }
+            } 
+            if (result.label.length() == 0) {
+                result.label = result.referencedMemberName;
+            }
+            result.href = containing.htmlPage() + '#' + result.memberInfo.anchor();
+        }
+
+        if (result.href == null && !skipHref) {
+            if (printOnErrors && (base == null || base.checkLevel())) {
+                Errors.error(Errors.UNRESOLVED_LINK, pos,
+                        "Unresolved link/see tag \"" + text.trim()
+                        + "\" in " + ((base != null) ? base.qualifiedName() : "[null]"));
+            }
+            result.makeError();
+        }
+        else if (result.memberInfo != null && !result.memberInfo.checkLevel()) {
+            if (printOnErrors && (base == null || base.checkLevel())) {
+                Errors.error(Errors.HIDDEN_LINK, pos,
+                        "Link to hidden member: " + text.trim());
+                result.href = null;
+            }
+            result.kind = "@seeJustLabel";
+        }
+        else if (result.classInfo != null && !result.classInfo.checkLevel()) {
+            if (printOnErrors && (base == null || base.checkLevel())) {
+                Errors.error(Errors.HIDDEN_LINK, pos,
+                        "Link to hidden class: " + text.trim() + " label=" + result.label);
+                result.href = null;
+            }
+            result.kind = "@seeJustLabel";
+        }
+        else if (result.packageInfo != null && !result.packageInfo.checkLevel()) {
+            if (printOnErrors && (base == null || base.checkLevel())) {
+                Errors.error(Errors.HIDDEN_LINK, pos,
+                        "Link to hidden package: " + text.trim());
+                result.href = null;
+            }
+            result.kind = "@seeJustLabel";
+        }
+
+        result.good = true;
+
+        return result;
+    }
+
+    public boolean checkLevel() {
+        if (memberInfo != null) {
+            return memberInfo.checkLevel();
+        }
+        if (classInfo != null) {
+            return classInfo.checkLevel();
+        }
+        if (packageInfo != null) {
+            return packageInfo.checkLevel();
+        }
+        return false;
+    }
+
+    /** turn this LinkReference into one with an error message */
+    private void makeError() {
+        //this.href = "ERROR(" + this.text.trim() + ")";
+        this.href = null;
+        if (this.label == null) {
+            this.label = "";
+        }
+        this.label = "ERROR(" + this.label + "/" + text.trim() + ")";
+    }
+
+    /** private. **/
+    private LinkReference() {
+    }
+}
diff --git a/build/tools/droiddoc/src/LiteralTagInfo.java b/build/tools/droiddoc/src/LiteralTagInfo.java
new file mode 100644 (file)
index 0000000..b39490d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class LiteralTagInfo extends TagInfo
+{
+    private static String encode(String t)
+    {
+        t = t.replace("&", "&amp;");
+        t = t.replace("<", "&lt;");
+        t = t.replace(">", "&gt;");
+        return t;
+    }
+
+    public LiteralTagInfo(String n, String k, String t, SourcePositionInfo sp)
+    {
+        super("Text", "Text", encode(t), sp);
+    }
+}
diff --git a/build/tools/droiddoc/src/MemberInfo.java b/build/tools/droiddoc/src/MemberInfo.java
new file mode 100644 (file)
index 0000000..05da583
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public abstract class MemberInfo extends DocInfo implements Comparable, Scoped
+{
+    public MemberInfo(String rawCommentText, String name, String signature,
+                        ClassInfo containingClass, ClassInfo realContainingClass,
+                        boolean isPublic, boolean isProtected,
+                        boolean isPackagePrivate, boolean isPrivate,
+                        boolean isFinal, boolean isStatic, boolean isSynthetic,
+                        String kind,
+                        SourcePositionInfo position,
+                        AnnotationInstanceInfo[] annotations)
+    {
+        super(rawCommentText, position);
+        mName = name;
+        mSignature = signature;
+        mContainingClass = containingClass;
+        mRealContainingClass = realContainingClass;
+        mIsPublic = isPublic;
+        mIsProtected = isProtected;
+        mIsPackagePrivate = isPackagePrivate;
+        mIsPrivate = isPrivate;
+        mIsFinal = isFinal;
+        mIsStatic = isStatic;
+        mIsSynthetic = isSynthetic;
+        mKind = kind;
+        mAnnotations = annotations;
+    }
+
+    public abstract boolean isExecutable();
+
+    public String anchor()
+    {
+        if (mSignature != null) {
+            return mName + mSignature;
+        } else {
+            return mName;
+        }
+    }
+
+    public String htmlPage() {
+        return mContainingClass.htmlPage() + "#" + anchor();
+    }
+
+    public int compareTo(Object that) {
+        return this.htmlPage().compareTo(((MemberInfo)that).htmlPage());
+    }
+
+    public String name()
+    {
+        return mName;
+    }
+
+    public String signature()
+    {
+        return mSignature;
+    }
+
+    public ClassInfo realContainingClass()
+    {
+        return mRealContainingClass;
+    }
+
+    public ClassInfo containingClass()
+    {
+        return mContainingClass;
+    }
+
+    public boolean isPublic()
+    {
+        return mIsPublic;
+    }
+
+    public boolean isProtected()
+    {
+        return mIsProtected;
+    }
+
+    public boolean isPackagePrivate()
+    {
+        return mIsPackagePrivate;
+    }
+
+    public boolean isPrivate()
+    {
+        return mIsPrivate;
+    }
+
+    public boolean isStatic()
+    {
+        return mIsStatic;
+    }
+
+    public boolean isFinal()
+    {
+        return mIsFinal;
+    }
+
+    public boolean isSynthetic()
+    {
+        return mIsSynthetic;
+    }
+
+    @Override
+    public ContainerInfo parent()
+    {
+        return mContainingClass;
+    }
+
+    public boolean checkLevel()
+    {
+        return DroidDoc.checkLevel(mIsPublic, mIsProtected,
+                mIsPackagePrivate, mIsPrivate, isHidden());
+    }
+
+    public String kind()
+    {
+        return mKind;
+    }
+
+    public AnnotationInstanceInfo[] annotations()
+    {
+        return mAnnotations;
+    }
+
+    ClassInfo mContainingClass;
+    ClassInfo mRealContainingClass;
+    String mName;
+    String mSignature;
+    boolean mIsPublic;
+    boolean mIsProtected;
+    boolean mIsPackagePrivate;
+    boolean mIsPrivate;
+    boolean mIsFinal;
+    boolean mIsStatic;
+    boolean mIsSynthetic;
+    String mKind;
+    private AnnotationInstanceInfo[] mAnnotations;
+
+}
+
diff --git a/build/tools/droiddoc/src/MethodInfo.java b/build/tools/droiddoc/src/MethodInfo.java
new file mode 100644 (file)
index 0000000..7f96b80
--- /dev/null
@@ -0,0 +1,670 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.clearsilver.HDF;
+
+import java.util.*;
+
+public class MethodInfo extends MemberInfo
+{
+    public static final Comparator<MethodInfo> comparator = new Comparator<MethodInfo>() {
+        public int compare(MethodInfo a, MethodInfo b) {
+            return a.name().compareTo(b.name());
+        }
+    };
+
+    private class InlineTags implements InheritedTags
+    {
+        public TagInfo[] tags()
+        {
+            return comment().tags();
+        }
+        public InheritedTags inherited()
+        {
+            MethodInfo m = findOverriddenMethod(name(), signature());
+            if (m != null) {
+                return m.inlineTags();
+            } else {
+                return null;
+            }
+        }
+    }
+
+    private static void addInterfaces(ClassInfo[] ifaces, ArrayList<ClassInfo> queue)
+    {
+        for (ClassInfo i: ifaces) {
+            queue.add(i);
+        }
+        for (ClassInfo i: ifaces) {
+            addInterfaces(i.interfaces(), queue);
+        }
+    }
+
+    // first looks for a superclass, and then does a breadth first search to
+    // find the least far away match
+    public MethodInfo findOverriddenMethod(String name, String signature)
+    {
+        if (mReturnType == null) {
+            // ctor
+            return null;
+        }
+        if (mOverriddenMethod != null) {
+            return mOverriddenMethod;
+        }
+
+        ArrayList<ClassInfo> queue = new ArrayList<ClassInfo>();
+        addInterfaces(containingClass().interfaces(), queue);
+        for (ClassInfo iface: queue) {
+            for (MethodInfo me: iface.methods()) {
+                if (me.name().equals(name)
+                        && me.signature().equals(signature)
+                        && me.inlineTags().tags() != null
+                        && me.inlineTags().tags().length > 0) {
+                    return me;
+                }
+            }
+        }
+        return null;
+    }
+
+    private static void addRealInterfaces(ClassInfo[] ifaces, ArrayList<ClassInfo> queue)
+    {
+        for (ClassInfo i: ifaces) {
+            queue.add(i);
+            if (i.realSuperclass() != null &&  i.realSuperclass().isAbstract()) {
+                queue.add(i.superclass());
+            }
+        }
+        for (ClassInfo i: ifaces) {
+            addInterfaces(i.realInterfaces(), queue);
+        }
+    }
+
+    public MethodInfo findRealOverriddenMethod(String name, String signature, HashSet notStrippable) {
+        if (mReturnType == null) {
+        // ctor
+        return null;
+        }
+        if (mOverriddenMethod != null) {
+            return mOverriddenMethod;
+        }
+
+        ArrayList<ClassInfo> queue = new ArrayList<ClassInfo>();
+        if (containingClass().realSuperclass() != null &&
+            containingClass().realSuperclass().isAbstract()) {
+            queue.add(containingClass());
+        }
+        addInterfaces(containingClass().realInterfaces(), queue);
+        for (ClassInfo iface: queue) {
+            for (MethodInfo me: iface.methods()) {
+                if (me.name().equals(name)
+                    && me.signature().equals(signature)
+                    && me.inlineTags().tags() != null
+                    && me.inlineTags().tags().length > 0
+                    && notStrippable.contains(me.containingClass())) {
+                return me;
+                }
+            }
+        }
+        return null;
+    }
+
+    public MethodInfo findSuperclassImplementation(HashSet notStrippable) {
+        if (mReturnType == null) {
+            // ctor
+            return null;
+        }
+        if (mOverriddenMethod != null) {
+            // Even if we're told outright that this was the overridden method, we want to
+            // be conservative and ignore mismatches of parameter types -- they arise from
+            // extending generic specializations, and we want to consider the derived-class
+            // method to be a non-override.
+            if (this.signature().equals(mOverriddenMethod.signature())) {
+                return mOverriddenMethod;
+            }
+        }
+
+        ArrayList<ClassInfo> queue = new ArrayList<ClassInfo>();
+        if (containingClass().realSuperclass() != null &&
+                containingClass().realSuperclass().isAbstract()) {
+            queue.add(containingClass());
+        }
+        addInterfaces(containingClass().realInterfaces(), queue);
+        for (ClassInfo iface: queue) {
+            for (MethodInfo me: iface.methods()) {
+                if (me.name().equals(this.name())
+                        && me.signature().equals(this.signature())
+                        && notStrippable.contains(me.containingClass())) {
+                    return me;
+                }
+            }
+        }
+        return null;
+    }
+
+    public ClassInfo findRealOverriddenClass(String name, String signature) {
+        if (mReturnType == null) {
+        // ctor
+        return null;
+        }
+        if (mOverriddenMethod != null) {
+            return mOverriddenMethod.mRealContainingClass;
+        }
+
+        ArrayList<ClassInfo> queue = new ArrayList<ClassInfo>();
+        if (containingClass().realSuperclass() != null &&
+            containingClass().realSuperclass().isAbstract()) {
+            queue.add(containingClass());
+        }
+        addInterfaces(containingClass().realInterfaces(), queue);
+        for (ClassInfo iface: queue) {
+            for (MethodInfo me: iface.methods()) {
+                if (me.name().equals(name)
+                    && me.signature().equals(signature)
+                    && me.inlineTags().tags() != null
+                    && me.inlineTags().tags().length > 0) {
+                return iface;
+                }
+            }
+        }
+        return null;
+    }
+
+    private class FirstSentenceTags implements InheritedTags
+    {
+        public TagInfo[] tags()
+        {
+            return comment().briefTags();
+        }
+        public InheritedTags inherited()
+        {
+            MethodInfo m = findOverriddenMethod(name(), signature());
+            if (m != null) {
+                return m.firstSentenceTags();
+            } else {
+                return null;
+            }
+        }
+    }
+
+    private class ReturnTags implements InheritedTags {
+        public TagInfo[] tags() {
+            return comment().returnTags();
+        }
+        public InheritedTags inherited() {
+            MethodInfo m = findOverriddenMethod(name(), signature());
+            if (m != null) {
+                return m.returnTags();
+            } else {
+                return null;
+            }
+        }
+    }
+
+    public boolean isDeprecated() {
+        boolean deprecated = false;
+        if (!mDeprecatedKnown) {
+            boolean commentDeprecated = (comment().deprecatedTags().length > 0);
+            boolean annotationDeprecated = false;
+            for (AnnotationInstanceInfo annotation : annotations()) {
+                if (annotation.type().qualifiedName().equals("java.lang.Deprecated")) {
+                    annotationDeprecated = true;
+                    break;
+                }
+            }
+
+            if (commentDeprecated != annotationDeprecated) {
+                Errors.error(Errors.DEPRECATION_MISMATCH, position(),
+                        "Method " + mContainingClass.qualifiedName() + "." + name()
+                        + ": @Deprecated annotation and @deprecated doc tag do not match");
+            }
+
+            mIsDeprecated = commentDeprecated | annotationDeprecated;
+            mDeprecatedKnown = true;
+        }
+        return mIsDeprecated;
+    }
+
+    public TypeInfo[] getTypeParameters(){
+        return mTypeParameters;
+    }
+
+    public MethodInfo cloneForClass(ClassInfo newContainingClass) {
+        MethodInfo result =  new MethodInfo(getRawCommentText(), mTypeParameters,
+                name(), signature(), newContainingClass, realContainingClass(),
+                isPublic(), isProtected(), isPackagePrivate(), isPrivate(), isFinal(), isStatic(),
+                isSynthetic(), mIsAbstract, mIsSynchronized, mIsNative, mIsAnnotationElement,
+                kind(), mFlatSignature, mOverriddenMethod,
+                mReturnType, mParameters, mThrownExceptions, position(), annotations());
+        result.init(mDefaultAnnotationElementValue);
+        return result;
+    }
+
+    public MethodInfo(String rawCommentText, TypeInfo[] typeParameters, String name,
+                        String signature, ClassInfo containingClass, ClassInfo realContainingClass,
+                        boolean isPublic, boolean isProtected,
+                        boolean isPackagePrivate, boolean isPrivate,
+                        boolean isFinal, boolean isStatic, boolean isSynthetic,
+                        boolean isAbstract, boolean isSynchronized, boolean isNative,
+                        boolean isAnnotationElement, String kind,
+                        String flatSignature, MethodInfo overriddenMethod,
+                        TypeInfo returnType, ParameterInfo[] parameters,
+                        ClassInfo[] thrownExceptions, SourcePositionInfo position,
+                        AnnotationInstanceInfo[] annotations)
+    {
+        // Explicitly coerce 'final' state of Java6-compiled enum values() method, to match
+        // the Java5-emitted base API description.
+        super(rawCommentText, name, signature, containingClass, realContainingClass,
+                isPublic, isProtected, isPackagePrivate, isPrivate,
+                ((name.equals("values") && containingClass.isEnum()) ? true : isFinal),
+                isStatic, isSynthetic, kind, position, annotations);
+
+        // The underlying MethodDoc for an interface's declared methods winds up being marked
+        // non-abstract.  Correct that here by looking at the immediate-parent class, and marking
+        // this method abstract if it is an unimplemented interface method.
+        if (containingClass.isInterface()) {
+            isAbstract = true;
+        }
+
+        mReasonOpened = "0:0";
+        mIsAnnotationElement = isAnnotationElement;
+        mTypeParameters = typeParameters;
+        mIsAbstract = isAbstract;
+        mIsSynchronized = isSynchronized;
+        mIsNative = isNative;
+        mFlatSignature = flatSignature;
+        mOverriddenMethod = overriddenMethod;
+        mReturnType = returnType;
+        mParameters = parameters;
+        mThrownExceptions = thrownExceptions;
+    }
+
+    public void init(AnnotationValueInfo defaultAnnotationElementValue)
+    {
+        mDefaultAnnotationElementValue = defaultAnnotationElementValue;
+    }
+
+    public boolean isAbstract()
+    {
+        return mIsAbstract;
+    }
+
+    public boolean isSynchronized()
+    {
+        return mIsSynchronized;
+    }
+
+    public boolean isNative()
+    {
+        return mIsNative;
+    }
+
+    public String flatSignature()
+    {
+        return mFlatSignature;
+    }
+
+    public InheritedTags inlineTags()
+    {
+        return new InlineTags();
+    }
+
+    public InheritedTags firstSentenceTags()
+    {
+        return new FirstSentenceTags();
+    }
+
+    public InheritedTags returnTags() {
+        return new ReturnTags();
+    }
+
+    public TypeInfo returnType()
+    {
+        return mReturnType;
+    }
+
+    public String prettySignature()
+    {
+        String s = "(";
+        int N = mParameters.length;
+        for (int i=0; i<N; i++) {
+            ParameterInfo p = mParameters[i];
+            TypeInfo t = p.type();
+            if (t.isPrimitive()) {
+                s += t.simpleTypeName();
+            } else {
+                s += t.asClassInfo().name();
+            }
+            if (i != N-1) {
+                s += ',';
+            }
+        }
+        s += ')';
+        return s;
+    }
+
+    /**
+     * Returns a name consistent with the {@link
+     * com.android.apicheck.MethodInfo#getHashableName()}.
+     */
+    public String getHashableName() {
+        StringBuilder result = new StringBuilder();
+        result.append(name());
+        for (int p = 0; p < mParameters.length; p++) {
+            result.append(":");
+            if (p == mParameters.length - 1 && isVarArgs()) {
+                // TODO: note that this does not attempt to handle hypothetical
+                // vararg methods whose last parameter is a list of arrays, e.g.
+                // "Object[]...".
+                result.append(mParameters[p].type().fullNameNoDimension(typeVariables()))
+                        .append("...");
+            } else {
+                result.append(mParameters[p].type().fullName(typeVariables()));
+            }
+        }
+        return result.toString();
+    }
+
+    private boolean inList(ClassInfo item, ThrowsTagInfo[] list)
+    {
+        int len = list.length;
+        String qn = item.qualifiedName();
+        for (int i=0; i<len; i++) {
+            ClassInfo ex = list[i].exception();
+            if (ex != null && ex.qualifiedName().equals(qn)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public ThrowsTagInfo[] throwsTags()
+    {
+        if (mThrowsTags == null) {
+            ThrowsTagInfo[] documented = comment().throwsTags();
+            ArrayList<ThrowsTagInfo> rv = new ArrayList<ThrowsTagInfo>();
+
+            int len = documented.length;
+            for (int i=0; i<len; i++) {
+                rv.add(documented[i]);
+            }
+
+            ClassInfo[] all = mThrownExceptions;
+            len = all.length;
+            for (int i=0; i<len; i++) {
+                ClassInfo cl = all[i];
+                if (documented == null || !inList(cl, documented)) {
+                    rv.add(new ThrowsTagInfo("@throws", "@throws",
+                                        cl.qualifiedName(), cl, "",
+                                        containingClass(), position()));
+                }
+            }
+            mThrowsTags = rv.toArray(new ThrowsTagInfo[rv.size()]);
+        }
+        return mThrowsTags;
+    }
+
+    private static int indexOfParam(String name, String[] list)
+    {
+        final int N = list.length;
+        for (int i=0; i<N; i++) {
+            if (name.equals(list[i])) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    public ParamTagInfo[] paramTags()
+    {
+        if (mParamTags == null) {
+            final int N = mParameters.length;
+
+            String[] names = new String[N];
+            String[] comments = new String[N];
+            SourcePositionInfo[] positions = new SourcePositionInfo[N];
+
+            // get the right names so we can handle our names being different from
+            // our parent's names.
+            for (int i=0; i<N; i++) {
+                names[i] = mParameters[i].name();
+                comments[i] = "";
+                positions[i] = mParameters[i].position();
+            }
+
+            // gather our comments, and complain about misnamed @param tags
+            for (ParamTagInfo tag: comment().paramTags()) {
+                int index = indexOfParam(tag.parameterName(), names);
+                if (index >= 0) {
+                    comments[index] = tag.parameterComment();
+                    positions[index] = tag.position();
+                } else {
+                    Errors.error(Errors.UNKNOWN_PARAM_TAG_NAME, tag.position(),
+                            "@param tag with name that doesn't match the parameter list: '"
+                            + tag.parameterName() + "'");
+                }
+            }
+
+            // get our parent's tags to fill in the blanks
+            MethodInfo overridden = this.findOverriddenMethod(name(), signature());
+            if (overridden != null) {
+                ParamTagInfo[] maternal = overridden.paramTags();
+                for (int i=0; i<N; i++) {
+                    if (comments[i].equals("")) {
+                        comments[i] = maternal[i].parameterComment();
+                        positions[i] = maternal[i].position();
+                    }
+                }
+            }
+
+            // construct the results, and cache them for next time
+            mParamTags = new ParamTagInfo[N];
+            for (int i=0; i<N; i++) {
+                mParamTags[i] = new ParamTagInfo("@param", "@param", names[i] + " " + comments[i],
+                        parent(), positions[i]);
+
+                // while we're here, if we find any parameters that are still undocumented at this
+                // point, complain. (this warning is off by default, because it's really, really
+                // common; but, it's good to be able to enforce it)
+                if (comments[i].equals("")) {
+                    Errors.error(Errors.UNDOCUMENTED_PARAMETER, positions[i],
+                            "Undocumented parameter '" + names[i] + "' on method '"
+                            + name() + "'");
+                }
+            }
+        }
+        return mParamTags;
+    }
+
+    public SeeTagInfo[] seeTags()
+    {
+        SeeTagInfo[] result = comment().seeTags();
+        if (result == null) {
+            if (mOverriddenMethod != null) {
+                result = mOverriddenMethod.seeTags();
+            }
+        }
+        return result;
+    }
+
+    public TagInfo[] deprecatedTags()
+    {
+        TagInfo[] result = comment().deprecatedTags();
+        if (result.length == 0) {
+            if (comment().undeprecateTags().length == 0) {
+                if (mOverriddenMethod != null) {
+                    result = mOverriddenMethod.deprecatedTags();
+                }
+            }
+        }
+        return result;
+    }
+
+    public ParameterInfo[] parameters()
+    {
+        return mParameters;
+    }
+
+
+    public boolean matchesParams(String[] params, String[] dimensions)
+    {
+        if (mParamStrings == null) {
+            ParameterInfo[] mine = mParameters;
+            int len = mine.length;
+            if (len != params.length) {
+                return false;
+            }
+            for (int i=0; i<len; i++) {
+                TypeInfo t = mine[i].type();
+                if (!t.dimension().equals(dimensions[i])) {
+                    return false;
+                }
+                String qn = t.qualifiedTypeName();
+                String s = params[i];
+                int slen = s.length();
+                int qnlen = qn.length();
+                if (!(qn.equals(s) ||
+                        ((slen+1)<qnlen && qn.charAt(qnlen-slen-1)=='.'
+                         && qn.endsWith(s)))) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    public void makeHDF(HDF data, String base)
+    {
+        data.setValue(base + ".kind", kind());
+        data.setValue(base + ".name", name());
+        data.setValue(base + ".href", htmlPage());
+        data.setValue(base + ".anchor", anchor());
+
+        if (mReturnType != null) {
+            returnType().makeHDF(data, base + ".returnType", false, typeVariables());
+            data.setValue(base + ".abstract", mIsAbstract ? "abstract" : "");
+        }
+
+        data.setValue(base + ".synchronized", mIsSynchronized ? "synchronized" : "");
+        data.setValue(base + ".final", isFinal() ? "final" : "");
+        data.setValue(base + ".static", isStatic() ? "static" : "");
+
+        TagInfo.makeHDF(data, base + ".shortDescr", firstSentenceTags());
+        TagInfo.makeHDF(data, base + ".descr", inlineTags());
+        TagInfo.makeHDF(data, base + ".deprecated", deprecatedTags());
+        TagInfo.makeHDF(data, base + ".seeAlso", seeTags());
+        data.setValue(base + ".since", getSince());
+        ParamTagInfo.makeHDF(data, base + ".paramTags", paramTags());
+        AttrTagInfo.makeReferenceHDF(data, base + ".attrRefs", comment().attrTags());
+        ThrowsTagInfo.makeHDF(data, base + ".throws", throwsTags());
+        ParameterInfo.makeHDF(data, base + ".params", parameters(), isVarArgs(), typeVariables());
+        if (isProtected()) {
+            data.setValue(base + ".scope", "protected");
+        }
+        else if (isPublic()) {
+            data.setValue(base + ".scope", "public");
+        }
+        TagInfo.makeHDF(data, base + ".returns", returnTags());
+
+        if (mTypeParameters != null) {
+            TypeInfo.makeHDF(data, base + ".generic.typeArguments", mTypeParameters, false);
+        }
+    }
+
+    public HashSet<String> typeVariables()
+    {
+        HashSet<String> result = TypeInfo.typeVariables(mTypeParameters);
+        ClassInfo cl = containingClass();
+        while (cl != null) {
+            TypeInfo[] types = cl.asTypeInfo().typeArguments();
+            if (types != null) {
+                TypeInfo.typeVariables(types, result);
+            }
+            cl = cl.containingClass();
+        }
+        return result;
+    }
+
+    @Override
+    public boolean isExecutable()
+    {
+        return true;
+    }
+
+    public ClassInfo[] thrownExceptions()
+    {
+        return mThrownExceptions;
+    }
+
+    public String typeArgumentsName(HashSet<String> typeVars)
+    {
+        if (mTypeParameters == null || mTypeParameters.length == 0) {
+            return "";
+        } else {
+            return TypeInfo.typeArgumentsName(mTypeParameters, typeVars);
+        }
+    }
+
+    public boolean isAnnotationElement()
+    {
+        return mIsAnnotationElement;
+    }
+
+    public AnnotationValueInfo defaultAnnotationElementValue()
+    {
+        return mDefaultAnnotationElementValue;
+    }
+
+    public void setVarargs(boolean set){
+        mIsVarargs = set;
+    }
+    public boolean isVarArgs(){
+      return mIsVarargs;
+    }
+
+    @Override
+    public String toString(){
+      return this.name();
+    }
+
+    public void setReason(String reason) {
+        mReasonOpened = reason;
+    }
+
+    public String getReason() {
+        return mReasonOpened;
+    }
+
+    private String mFlatSignature;
+    private MethodInfo mOverriddenMethod;
+    private TypeInfo mReturnType;
+    private boolean mIsAnnotationElement;
+    private boolean mIsAbstract;
+    private boolean mIsSynchronized;
+    private boolean mIsNative;
+    private boolean mIsVarargs;
+    private boolean mDeprecatedKnown;
+    private boolean mIsDeprecated;
+    private ParameterInfo[] mParameters;
+    private ClassInfo[] mThrownExceptions;
+    private String[] mParamStrings;
+    ThrowsTagInfo[] mThrowsTags;
+    private ParamTagInfo[] mParamTags;
+    private TypeInfo[] mTypeParameters;
+    private AnnotationValueInfo mDefaultAnnotationElementValue;
+    private String mReasonOpened;
+}
+
diff --git a/build/tools/droiddoc/src/NavTree.java b/build/tools/droiddoc/src/NavTree.java
new file mode 100644 (file)
index 0000000..0469fdc
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.clearsilver.HDF;
+
+import java.util.ArrayList;
+
+public class NavTree {
+
+    public static void writeNavTree(String dir) {
+        ArrayList<Node> children = new ArrayList();
+        for (PackageInfo pkg: DroidDoc.choosePackages()) {
+            children.add(makePackageNode(pkg));
+        }
+        Node node = new Node("Reference", dir + "packages.html", children, null);
+
+        StringBuilder buf = new StringBuilder();
+        if (false) {
+            // if you want a root node
+            buf.append("[");
+            node.render(buf);
+            buf.append("]");
+        } else {
+            // if you don't want a root node
+            node.renderChildren(buf);
+        }
+
+        HDF data = DroidDoc.makeHDF();
+        data.setValue("reference_tree", buf.toString());
+        ClearPage.write(data, "navtree_data.cs", "navtree_data.js");
+    }
+
+    private static Node makePackageNode(PackageInfo pkg) {
+        ArrayList<Node> children = new ArrayList();
+
+        children.add(new Node("Description", pkg.fullDescriptionHtmlPage(), null, null));
+
+        addClassNodes(children, "Interfaces", pkg.interfaces());
+        addClassNodes(children, "Classes", pkg.ordinaryClasses());
+        addClassNodes(children, "Enums", pkg.enums());
+        addClassNodes(children, "Exceptions", pkg.exceptions());
+        addClassNodes(children, "Errors", pkg.errors());
+
+        return new Node(pkg.name(), pkg.htmlPage(), children, pkg.getSince());
+    }
+
+    private static void addClassNodes(ArrayList<Node> parent, String label, ClassInfo[] classes) {
+        ArrayList<Node> children = new ArrayList();
+
+        for (ClassInfo cl: classes) {
+            if (cl.checkLevel()) {
+                children.add(new Node(cl.name(), cl.htmlPage(), null, cl.getSince()));
+            }
+        }
+
+        if (children.size() > 0) {
+            parent.add(new Node(label, null, children, null));
+        }
+    }
+
+    private static class Node {
+        private String mLabel;
+        private String mLink;
+        ArrayList<Node> mChildren;
+        private String mSince;
+
+        Node(String label, String link, ArrayList<Node> children, String since) {
+            mLabel = label;
+            mLink = link;
+            mChildren = children;
+            mSince = since;
+        }
+
+        static void renderString(StringBuilder buf, String s) {
+            if (s == null) {
+                buf.append("null");
+            } else {
+                buf.append('"');
+                final int N = s.length();
+                for (int i=0; i<N; i++) {
+                    char c = s.charAt(i);
+                    if (c >= ' ' && c <= '~' && c != '"' && c != '\\') {
+                        buf.append(c);
+                    } else {
+                        buf.append("\\u");
+                        for (int j=0; i<4; i++) {
+                            char x = (char)(c & 0x000f);
+                            if (x > 10) {
+                                x = (char)(x - 10 + 'a');
+                            } else {
+                                x = (char)(x + '0');
+                            }
+                            buf.append(x);
+                            c >>= 4;
+                        }
+                    }
+                }
+                buf.append('"');
+            }
+        }
+
+        void renderChildren(StringBuilder buf) {
+            ArrayList<Node> list = mChildren;
+            if (list == null || list.size() == 0) {
+                // We output null for no children.  That way empty lists here can just
+                // be a byproduct of how we generate the lists.
+                buf.append("null");
+            } else {
+                buf.append("[ ");
+                final int N = list.size();
+                for (int i=0; i<N; i++) {
+                    list.get(i).render(buf);
+                    if (i != N-1) {
+                        buf.append(", ");
+                    }
+                }
+                buf.append(" ]\n");
+            }
+        }
+
+        void render(StringBuilder buf) {
+            buf.append("[ ");
+            renderString(buf, mLabel);
+            buf.append(", ");
+            renderString(buf, mLink);
+            buf.append(", ");
+            renderChildren(buf);
+            buf.append(", ");
+            renderString(buf, mSince);
+            buf.append(" ]");
+        }
+    }
+}
diff --git a/build/tools/droiddoc/src/PackageInfo.java b/build/tools/droiddoc/src/PackageInfo.java
new file mode 100644 (file)
index 0000000..17ad1b7
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.sun.javadoc.*;
+import com.sun.tools.doclets.*;
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+import java.util.*;
+import java.io.*;
+
+public class PackageInfo extends DocInfo implements ContainerInfo
+{
+    public static final Comparator<PackageInfo> comparator = new Comparator<PackageInfo>() {
+        public int compare(PackageInfo a, PackageInfo b) {
+            return a.name().compareTo(b.name());
+        }
+    };
+
+    public PackageInfo(PackageDoc pkg, String name, SourcePositionInfo position)
+    {
+        super(pkg.getRawCommentText(), position);
+        mName = name;
+
+        if (pkg == null) {
+            throw new RuntimeException("pkg is null");
+        }
+        mPackage = pkg;
+    }
+
+    public String htmlPage()
+    {
+        String s = mName;
+        s = s.replace('.', '/');
+        s += "/package-summary.html";
+        s = DroidDoc.javadocDir + s;
+        return s;
+    }
+
+    public String fullDescriptionHtmlPage() {
+        String s = mName;
+        s = s.replace('.', '/');
+        s += "/package-descr.html";
+        s = DroidDoc.javadocDir + s;
+        return s;
+    }
+
+    @Override
+    public ContainerInfo parent()
+    {
+        return null;
+    }
+
+    @Override
+    public boolean isHidden()
+    {
+        return comment().isHidden();
+    }
+
+    public boolean checkLevel() {
+        // TODO should return false if all classes are hidden but the package isn't.
+        // We don't have this so I'm not doing it now.
+        return !isHidden();
+    }
+
+    public String name()
+    {
+        return mName;
+    }
+
+    public String qualifiedName()
+    {
+        return mName;
+    }
+
+    public TagInfo[] inlineTags()
+    {
+        return comment().tags();
+    }
+
+    public TagInfo[] firstSentenceTags()
+    {
+        return comment().briefTags();
+    }
+
+    public static ClassInfo[] filterHidden(ClassInfo[] classes)
+    {
+        ArrayList<ClassInfo> out = new ArrayList<ClassInfo>();
+
+        for (ClassInfo cl: classes) {
+            if (!cl.isHidden()) {
+                out.add(cl);
+            }
+        }
+
+        return out.toArray(new ClassInfo[0]);
+    }
+
+    public void makeLink(HDF data, String base)
+    {
+        if (checkLevel()) {
+            data.setValue(base + ".link", htmlPage());
+        }
+        data.setValue(base + ".name", name());
+        data.setValue(base + ".since", getSince());
+    }
+
+    public void makeClassLinkListHDF(HDF data, String base)
+    {
+        makeLink(data, base);
+        ClassInfo.makeLinkListHDF(data, base + ".interfaces", interfaces());
+        ClassInfo.makeLinkListHDF(data, base + ".classes", ordinaryClasses());
+        ClassInfo.makeLinkListHDF(data, base + ".enums", enums());
+        ClassInfo.makeLinkListHDF(data, base + ".exceptions", exceptions());
+        ClassInfo.makeLinkListHDF(data, base + ".errors", errors());
+        data.setValue(base + ".since", getSince());
+    }
+
+    public ClassInfo[] interfaces()
+    {
+        if (mInterfaces == null) {
+            mInterfaces = ClassInfo.sortByName(filterHidden(Converter.convertClasses(
+                            mPackage.interfaces())));
+        }
+        return mInterfaces;
+    }
+
+    public ClassInfo[] ordinaryClasses()
+    {
+        if (mOrdinaryClasses == null) {
+            mOrdinaryClasses = ClassInfo.sortByName(filterHidden(Converter.convertClasses(
+                            mPackage.ordinaryClasses())));
+        }
+        return mOrdinaryClasses;
+    }
+
+    public ClassInfo[] enums()
+    {
+        if (mEnums == null) {
+            mEnums = ClassInfo.sortByName(filterHidden(Converter.convertClasses(mPackage.enums())));
+        }
+        return mEnums;
+    }
+
+    public ClassInfo[] exceptions()
+    {
+        if (mExceptions == null) {
+            mExceptions = ClassInfo.sortByName(filterHidden(Converter.convertClasses(
+                        mPackage.exceptions())));
+        }
+        return mExceptions;
+    }
+
+    public ClassInfo[] errors()
+    {
+        if (mErrors == null) {
+            mErrors = ClassInfo.sortByName(filterHidden(Converter.convertClasses(
+                        mPackage.errors())));
+        }
+        return mErrors;
+    }
+
+    // in hashed containers, treat the name as the key
+    @Override
+    public int hashCode() {
+        return mName.hashCode();
+    }
+
+    private String mName;
+    private PackageDoc mPackage;
+    private ClassInfo[] mInterfaces;
+    private ClassInfo[] mOrdinaryClasses;
+    private ClassInfo[] mEnums;
+    private ClassInfo[] mExceptions;
+    private ClassInfo[] mErrors;
+}
+
diff --git a/build/tools/droiddoc/src/ParamTagInfo.java b/build/tools/droiddoc/src/ParamTagInfo.java
new file mode 100644 (file)
index 0000000..d6f2b6b
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+
+public class ParamTagInfo extends ParsedTagInfo
+{
+    static final Pattern PATTERN = Pattern.compile(
+                                "([^ \t\r\n]+)[ \t\r\n]+(.*)",
+                                Pattern.DOTALL);
+
+    private boolean mIsTypeParameter;
+    private String mParameterComment;
+    private String mParameterName;
+
+    ParamTagInfo(String name, String kind, String text, ContainerInfo base,
+            SourcePositionInfo sp)
+    {
+        super(name, kind, text, base, sp);
+
+        Matcher m = PATTERN.matcher(text);
+        if (m.matches()) {
+            mParameterName = m.group(1);
+            mParameterComment = m.group(2);
+            int len = mParameterName.length();
+            mIsTypeParameter = len > 2
+                                && mParameterName.charAt(0) == '<'
+                                && mParameterName.charAt(len-1) == '>';
+        } else {
+            mParameterName = text.trim();
+            mParameterComment = "";
+            mIsTypeParameter = false;
+        }
+        setCommentText(mParameterComment);
+    }
+
+    ParamTagInfo(String name, String kind, String text,
+                            boolean isTypeParameter, String parameterComment,
+                            String parameterName, ContainerInfo base,
+                            SourcePositionInfo sp)
+    {
+        super(name, kind, text, base, sp);
+        mIsTypeParameter = isTypeParameter;
+        mParameterComment = parameterComment;
+        mParameterName = parameterName;
+    }
+
+    public boolean isTypeParameter()
+    {
+        return mIsTypeParameter;
+    }
+
+    public String parameterComment()
+    {
+        return mParameterComment;
+    }
+
+    public String parameterName()
+    {
+        return mParameterName;
+    }
+
+    @Override
+    public void makeHDF(HDF data, String base)
+    {
+        data.setValue(base + ".name", parameterName());
+        data.setValue(base + ".isTypeParameter", isTypeParameter() ? "1" : "0");
+        TagInfo.makeHDF(data, base + ".comment", commentTags());
+    }
+
+    public static void makeHDF(HDF data, String base, ParamTagInfo[] tags)
+    {
+        for (int i=0; i<tags.length; i++) {
+            // don't output if the comment is ""
+            if (!"".equals(tags[i].parameterComment())) {
+                tags[i].makeHDF(data, base + "." + i);
+            }
+        }
+    }
+}
diff --git a/build/tools/droiddoc/src/ParameterInfo.java b/build/tools/droiddoc/src/ParameterInfo.java
new file mode 100644 (file)
index 0000000..44608be
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+import java.util.HashSet;
+
+public class ParameterInfo
+{
+    ParameterInfo(String name, String typeName, TypeInfo type, SourcePositionInfo position)
+    {
+        mName = name;
+        mTypeName = typeName;
+        mType = type;
+        mPosition = position;
+    }
+
+    TypeInfo type()
+    {
+        return mType;
+    }
+
+    String name()
+    {
+        return mName;
+    }
+
+    String typeName()
+    {
+        return mTypeName;
+    }
+
+    SourcePositionInfo position()
+    {
+        return mPosition;
+    }
+
+    public void makeHDF(HDF data, String base, boolean isLastVararg,
+            HashSet<String> typeVariables)
+    {
+        data.setValue(base + ".name", this.name());
+        type().makeHDF(data, base + ".type", isLastVararg, typeVariables);
+    }
+
+    public static void makeHDF(HDF data, String base, ParameterInfo[] params,
+            boolean isVararg, HashSet<String> typeVariables)
+    {
+        for (int i=0; i<params.length; i++) {
+            params[i].makeHDF(data, base + "." + i,
+                    isVararg && (i == params.length - 1), typeVariables);
+        }
+    }
+    
+    String mName;
+    String mTypeName;
+    TypeInfo mType;
+    SourcePositionInfo mPosition;
+}
+
diff --git a/build/tools/droiddoc/src/ParsedTagInfo.java b/build/tools/droiddoc/src/ParsedTagInfo.java
new file mode 100644 (file)
index 0000000..c2e4806
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+import java.util.ArrayList;
+
+public class ParsedTagInfo extends TagInfo
+{
+    private ContainerInfo mContainer;
+    private String mCommentText;
+    private Comment mComment;
+
+    ParsedTagInfo(String name, String kind, String text, ContainerInfo base, SourcePositionInfo sp)
+    {
+        super(name, kind, text, SourcePositionInfo.findBeginning(sp, text));
+        mContainer = base;
+        mCommentText = text;
+    }
+
+    public TagInfo[] commentTags()
+    {
+        if (mComment == null) {
+            mComment = new Comment(mCommentText, mContainer, position());
+        }
+        return mComment.tags();
+    }
+
+    protected void setCommentText(String comment)
+    {
+        mCommentText = comment;
+    }
+
+    public static <T extends ParsedTagInfo> TagInfo[]
+    joinTags(T[] tags)
+    {
+        ArrayList<TagInfo> list = new ArrayList<TagInfo>();
+        final int N = tags.length;
+        for (int i=0; i<N; i++) {
+            TagInfo[] t = tags[i].commentTags();
+            final int M = t.length;
+            for (int j=0; j<M; j++) {
+                list.add(t[j]);
+            }
+        }
+        return list.toArray(new TagInfo[list.size()]);
+    }
+}
diff --git a/build/tools/droiddoc/src/Proofread.java b/build/tools/droiddoc/src/Proofread.java
new file mode 100644 (file)
index 0000000..ec9f523
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.IOException;
+import java.io.FileWriter;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+public class Proofread
+{
+    static FileWriter out = null;
+    static final Pattern WHITESPACE = Pattern.compile("\\r?\\n");
+    static final String INDENT = "        ";
+    static final String NEWLINE = "\n" + INDENT;
+
+    public static void initProofread(String filename)
+    {
+        try {
+            out = new FileWriter(filename);
+            out.write("javadoc proofread file: " + filename + "\n");
+        }
+        catch (IOException e) {
+            if (out != null) {
+                try {
+                    out.close();
+                }
+                catch (IOException ex) {
+                }
+                out = null;
+            }
+            System.err.println("error opening file: " + filename);
+        }
+    }
+
+    public static void finishProofread(String filename)
+    {
+        if (out == null) {
+            return;
+        }
+
+        try {
+            out.close();
+        }
+        catch (IOException e) {
+        }
+    }
+
+    public static void write(String s)
+    {
+        if (out == null) {
+            return ;
+        }
+        try {
+            out.write(s);
+        }
+        catch (IOException e) {
+        }
+    }
+
+    public static void writeIndented(String s)
+    {
+        s = s.trim();
+        Matcher m = WHITESPACE.matcher(s);
+        s = m.replaceAll(NEWLINE);
+        write(INDENT);
+        write(s);
+        write("\n");
+    }
+
+    public static void writeFileHeader(String filename)
+    {
+        write("\n\n=== ");
+        write(filename);
+        write(" ===\n");
+    }
+
+    public static void writeTagList(TagInfo[] tags)
+    {
+        if (out == null) {
+            return;
+        }
+
+        for (TagInfo t: tags) {
+            String k = t.kind();
+            if ("Text".equals(t.name())) {
+                writeIndented(t.text());
+            }
+            else if ("@more".equals(k)) {
+                writeIndented("");
+            }
+            else if ("@see".equals(k)) {
+                SeeTagInfo see = (SeeTagInfo)t;
+                String label = see.label();
+                if (label == null) {
+                    label = "";
+                }
+                writeIndented("{" + see.name() + " ... " + label + "}");
+            }
+            else if ("@code".equals(k)) {
+                writeIndented(t.text());
+            }
+            else if ("@samplecode".equals(k)) {
+                writeIndented(t.text());
+            }
+            else {
+                writeIndented("{" + (t.name() != null ? t.name() : "") + "/" +
+                        t.text() + "}");
+            }
+        }
+    }
+
+    public static void writePackages(String filename, TagInfo[] tags)
+    {
+        if (out == null) {
+            return;
+        }
+
+        writeFileHeader(filename);
+        writeTagList(tags);
+    }
+
+    public static void writePackage(String filename, TagInfo[] tags)
+    {
+        if (out == null) {
+            return;
+        }
+
+        writeFileHeader(filename);
+        writeTagList(tags);
+    }
+
+    public static void writeClass(String filename, ClassInfo cl)
+    {
+        if (out == null) {
+            return;
+        }
+
+        writeFileHeader(filename);
+        writeTagList(cl.inlineTags());
+
+        // enum constants
+        for (FieldInfo f: cl.enumConstants()) {
+            write("ENUM: " + f.name() + "\n");
+            writeTagList(f.inlineTags());
+        }
+
+        // fields
+        for (FieldInfo f: cl.selfFields()) {
+            write("FIELD: " + f.name() + "\n");
+            writeTagList(f.inlineTags());
+        }
+
+        // constructors
+        for (MethodInfo m: cl.constructors()) {
+            write("CONSTRUCTOR: " + m.name() + "\n");
+            writeTagList(m.inlineTags().tags());
+        }
+
+        // methods
+        for (MethodInfo m: cl.selfMethods()) {
+            write("METHOD: " + m.name() + "\n");
+            writeTagList(m.inlineTags().tags());
+        }
+    }
+}
diff --git a/build/tools/droiddoc/src/SampleCode.java b/build/tools/droiddoc/src/SampleCode.java
new file mode 100644 (file)
index 0000000..bf54445
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+import java.util.*;
+import java.io.*;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+
+public class SampleCode {
+    String mSource;
+    String mDest;
+    String mTitle;
+
+    public SampleCode(String source, String dest, String title) {
+        mSource = source;
+        mTitle = title;
+        int len = dest.length();
+        if (len > 1 && dest.charAt(len-1) != '/') {
+            mDest = dest + '/';
+        } else {
+            mDest = dest;
+        }
+    }
+
+    public void write(boolean offlineMode) {
+        File f = new File(mSource);
+        if (!f.isDirectory()) {
+            System.out.println("-samplecode not a directory: " + mSource);
+            return;
+        }
+        if (offlineMode) writeIndexOnly(f, mDest, offlineMode);
+        else writeDirectory(f, mDest);
+    }
+
+    public static String convertExtension(String s, String ext) {
+        return s.substring(0, s.lastIndexOf('.')) + ext;
+    }
+
+    public static String[] IMAGES = { ".png", ".jpg", ".gif" };
+    public static String[] TEMPLATED = { ".java", ".xml" };
+
+    public static boolean inList(String s, String[] list) {
+        for (String t: list) {
+            if (s.endsWith(t)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void writeDirectory(File dir, String relative) {
+        TreeSet<String> dirs = new TreeSet<String>();
+        TreeSet<String> files = new TreeSet<String>();
+
+        String subdir = relative; //.substring(mDest.length());
+
+        for (File f: dir.listFiles()) {
+            String name = f.getName();
+            if (name.startsWith(".") || name.startsWith("_")) {
+                continue;
+            }
+            if (f.isFile()) {
+                String out = relative + name;
+
+                if (inList(out, IMAGES)) {
+                    // copied directly
+                    ClearPage.copyFile(f, out);
+                    writeImagePage(f, convertExtension(out, DroidDoc.htmlExtension), subdir);
+                    files.add(name);
+                }
+                if (inList(out, TEMPLATED)) {
+                    // copied and goes through the template
+                    ClearPage.copyFile(f, out);
+                    writePage(f, convertExtension(out, DroidDoc.htmlExtension), subdir);
+                    files.add(name);
+                }
+                // else ignored
+            }
+            else if (f.isDirectory()) {
+                writeDirectory(f, relative + name + "/");
+                dirs.add(name);
+            }
+        }
+
+        // write the index page
+        int i;
+
+        HDF hdf = writeIndex(dir);
+        hdf.setValue("subdir", subdir);
+        i=0;
+        for (String d: dirs) {
+            hdf.setValue("subdirs." + i + ".name", d);
+            i++;
+        }
+        i=0;
+        for (String f: files) {
+            hdf.setValue("files." + i + ".name", f);
+            hdf.setValue("files." + i + ".href", convertExtension(f, ".html"));
+            i++;
+        }
+        
+        ClearPage.write(hdf, "sampleindex.cs", relative + "/index" + DroidDoc.htmlExtension);
+    }
+
+    public void writeIndexOnly(File dir, String relative, Boolean offline) {
+        HDF hdf = writeIndex(dir);
+        if (!offline) relative = "/" + relative;
+        ClearPage.write(hdf, "sampleindex.cs", relative + "index" +
+                        DroidDoc.htmlExtension);
+    }
+
+    public HDF writeIndex(File dir) {
+        HDF hdf = DroidDoc.makeHDF();
+
+        hdf.setValue("page.title", dir.getName() + " - " + mTitle);
+        hdf.setValue("projectTitle", mTitle);
+
+        String filename = dir.getPath() + "/_index.html";
+        String summary = SampleTagInfo.readFile(new SourcePositionInfo(filename,
+                          -1,-1), filename, "sample code", true, false, true);
+
+        if (summary == null) {
+            summary = "";
+        }
+        hdf.setValue("summary", summary);
+
+        return hdf;
+    }
+
+    public void writePage(File f, String out, String subdir) {
+        String name = f.getName();
+
+        String filename = f.getPath();
+        String data = SampleTagInfo.readFile(new SourcePositionInfo(filename, -1,-1), filename,
+                                                "sample code", true, true, true);
+        data = DroidDoc.escape(data);
+        
+        HDF hdf = DroidDoc.makeHDF();
+
+        hdf.setValue("page.title", name);
+        hdf.setValue("subdir", subdir);
+        hdf.setValue("realFile", name);
+        hdf.setValue("fileContents", data);
+
+        ClearPage.write(hdf, "sample.cs", out);
+    }
+
+    public void writeImagePage(File f, String out, String subdir) {
+        String name = f.getName();
+
+        String data = "<img src=\"" + name + "\" title=\"" + name + "\" />";
+        
+        HDF hdf = DroidDoc.makeHDF();
+
+        hdf.setValue("page.title", name);
+        hdf.setValue("subdir", subdir);
+        hdf.setValue("realFile", name);
+        hdf.setValue("fileContents", data);
+
+        ClearPage.write(hdf, "sample.cs", out);
+    }
+}
diff --git a/build/tools/droiddoc/src/SampleTagInfo.java b/build/tools/droiddoc/src/SampleTagInfo.java
new file mode 100644 (file)
index 0000000..c7ad1cc
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+
+import java.io.Reader;
+import java.io.IOException;
+import java.io.FileReader;
+import java.io.LineNumberReader;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+/*
+ * SampleTagInfo copies text from a given file into the javadoc comment.
+ *
+ * The @include tag copies the text verbatim from the given file.
+ *
+ * The @sample tag copies the text from the given file, stripping leading and
+ * trailing whitespace, and reducing the indent level of the text to the indent
+ * level of the first non-whitespace line.
+ *
+ * Both tags accept either a filename and an id or just a filename.  If no id
+ * is provided, the entire file is copied.  If an id is provided, the lines
+ * in the given file between the first two lines containing BEGIN_INCLUDE(id)
+ * and END_INCLUDE(id), for the given id, are copied.  The id may be only
+ * letters, numbers and underscore (_).
+ *
+ * Four examples:
+ * {@include samples/ApiDemos/src/com/google/app/Notification1.java}
+ * {@sample samples/ApiDemos/src/com/google/app/Notification1.java}
+ * {@include samples/ApiDemos/src/com/google/app/Notification1.java Bleh}
+ * {@sample samples/ApiDemos/src/com/google/app/Notification1.java Bleh}
+ *
+ */
+public class SampleTagInfo extends TagInfo
+{
+    static final int STATE_BEGIN = 0;
+    static final int STATE_MATCHING = 1;
+
+    static final Pattern TEXT = Pattern.compile(
+                "[\r\n \t]*([^\r\n \t]*)[\r\n \t]*([0-9A-Za-z_]*)[\r\n \t]*",
+                Pattern.DOTALL);
+
+    private static final String BEGIN_INCLUDE = "BEGIN_INCLUDE";
+    private static final String END_INCLUDE = "END_INCLUDE";
+
+    private ContainerInfo mBase;
+    private String mIncluded;
+
+    public static String escapeHtml(String str) {
+        return str.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;");
+    }
+
+    private static boolean isIncludeLine(String str) {
+        return str.indexOf(BEGIN_INCLUDE)>=0 || str.indexOf(END_INCLUDE)>=0;
+    }
+
+    SampleTagInfo(String name, String kind, String text, ContainerInfo base,
+            SourcePositionInfo position)
+    {
+        super(name, kind, text, position);
+        mBase = base;
+
+        Matcher m = TEXT.matcher(text);
+        if (!m.matches()) {
+            Errors.error(Errors.BAD_INCLUDE_TAG, position, "Bad @include tag: "
+                    + text);
+            return;
+        }
+        String filename = m.group(1);
+        String id = m.group(2);
+        boolean trim = "@sample".equals(name);
+
+        if (id == null || "".equals(id)) {
+            mIncluded = readFile(position, filename, id, trim, true, false);
+        } else {
+            mIncluded = loadInclude(position, filename, id, trim);
+        }
+
+        if (mIncluded == null) {
+            Errors.error(Errors.BAD_INCLUDE_TAG, position, "include tag '" + id
+                    + "' not found in file: " + filename);
+        }
+    }
+
+    static String getTrimString(String line)
+    {
+        int i = 0;
+        int len = line.length();
+        for (; i<len; i++) {
+            char c = line.charAt(i);
+            if (c != ' ' && c != '\t') {
+                break;
+            }
+        }
+        if (i == len) {
+            return null;
+        } else {
+            return line.substring(0, i);
+        }
+    }
+
+    static String loadInclude(SourcePositionInfo pos, String filename,
+                                String id, boolean trim)
+    {
+        Reader input = null;
+        StringBuilder result = new StringBuilder();
+
+        String begin = BEGIN_INCLUDE + "(" + id + ")";
+        String end = END_INCLUDE + "(" + id + ")";
+
+        try {
+            input = new FileReader(filename);
+            LineNumberReader lines = new LineNumberReader(input);
+
+            int state = STATE_BEGIN;
+
+            int trimLength = -1;
+            String trimString = null;
+            int trailing = 0;
+
+            while (true) {
+                String line = lines.readLine();
+                if (line == null) {
+                    return null;
+                }
+                switch (state) {
+                case STATE_BEGIN:
+                    if (line.indexOf(begin) >= 0) {
+                        state = STATE_MATCHING;
+                    }
+                    break;
+                case STATE_MATCHING:
+                    if (line.indexOf(end) >= 0) {
+                        return result.substring(0);
+                    } else {
+                        boolean empty = "".equals(line.trim());
+                        if (trim) {
+                            if (isIncludeLine(line)) {
+                                continue;
+                            }
+                            if (trimLength < 0 && !empty) {
+                                trimString = getTrimString(line);
+                                if (trimString != null) {
+                                    trimLength = trimString.length();
+                                }
+                            }
+                            if (trimLength >= 0 && line.length() > trimLength) {
+                                boolean trimThisLine = true;
+                                for (int i=0; i<trimLength; i++) {
+                                    if (line.charAt(i) != trimString.charAt(i)){
+                                        trimThisLine = false;
+                                        break;
+                                    }
+                                }
+                                if (trimThisLine) {
+                                    line = line.substring(trimLength);
+                                }
+                            }
+                            if (trimLength >= 0) {
+                                if (!empty) {
+                                    for (int i=0; i<trailing; i++) {
+                                        result.append('\n');
+                                    }
+                                    line = escapeHtml(line);
+                                    result.append(line);
+                                    trailing = 1;  // add \n next time, maybe
+                                } else {
+                                    trailing++;
+                                }
+                            }
+                        } else {
+                            result.append(line);
+                            result.append('\n');
+                        }
+                    }
+                    break;
+                }
+            }
+        }
+        catch (IOException e) {
+            Errors.error(Errors.BAD_INCLUDE_TAG, pos, "Error reading file for"
+                    + " include \"" + id + "\" " + filename);
+        }
+        finally {
+            if (input != null) {
+                try {
+                    input.close();
+                }
+                catch (IOException ex) {
+                }
+            }
+        }
+        Errors.error(Errors.BAD_INCLUDE_TAG, pos, "Did not find " + end
+                + " in file " + filename);
+        return null;
+    }
+
+    static String readFile(SourcePositionInfo pos, String filename,
+                                String id, boolean trim, boolean escape,
+                                boolean errorOk)
+    {
+        Reader input = null;
+        StringBuilder result = new StringBuilder();
+        int trailing = 0;
+        boolean started = false;
+        try {
+            input = new FileReader(filename);
+            LineNumberReader lines = new LineNumberReader(input);
+
+            while (true) {
+                String line = lines.readLine();
+                if (line == null) {
+                    break;
+                }
+                if (trim) {
+                    if (isIncludeLine(line)) {
+                        continue;
+                    }
+                    if (!"".equals(line.trim())) {
+                        if (started) {
+                            for (int i=0; i<trailing; i++) {
+                                result.append('\n');
+                            }
+                        }
+                        if (escape) {
+                            line = escapeHtml(line);
+                        }
+                        result.append(line);
+                        trailing = 1;  // add \n next time, maybe
+                        started = true;
+                    } else {
+                        if (started) {
+                            trailing++;
+                        }
+                    }
+                } else {
+                    result.append(line);
+                    result.append('\n');
+                }
+            }
+        }
+        catch (IOException e) {
+            if (errorOk) {
+                return null;
+            } else {
+                Errors.error(Errors.BAD_INCLUDE_TAG, pos, "Error reading file for"
+                        + " include \"" + id + "\" " + filename);
+            }
+        }
+        finally {
+            if (input != null) {
+                try {
+                    input.close();
+                }
+                catch (IOException ex) {
+                }
+            }
+        }
+        return result.substring(0);
+    }
+
+    @Override
+    public void makeHDF(HDF data, String base)
+    {
+        data.setValue(base + ".name", name());
+        data.setValue(base + ".kind", kind());
+        if (mIncluded != null) {
+            data.setValue(base + ".text", mIncluded);
+        } else {
+            data.setValue(base + ".text", "INCLUDE_ERROR");
+        }
+    }
+}
+
diff --git a/build/tools/droiddoc/src/Scoped.java b/build/tools/droiddoc/src/Scoped.java
new file mode 100644 (file)
index 0000000..cca61ed
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public interface Scoped {
+    boolean isPublic();
+    boolean isProtected();
+    boolean isPackagePrivate();
+    boolean isPrivate();
+    boolean isHidden();
+}
diff --git a/build/tools/droiddoc/src/SeeTagInfo.java b/build/tools/droiddoc/src/SeeTagInfo.java
new file mode 100644 (file)
index 0000000..8420ed3
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+import java.util.ArrayList;
+
+public class SeeTagInfo extends TagInfo
+{
+    private ContainerInfo mBase;
+    LinkReference mLink;
+
+    SeeTagInfo(String name, String kind, String text, ContainerInfo base,
+            SourcePositionInfo position)
+    {
+        super(name, kind, text, position);
+        mBase = base;
+    }
+
+    protected LinkReference linkReference() {
+        if (mLink == null) {
+            mLink = LinkReference.parse(text(), mBase, position(),
+                           (!"@see".equals(name())) && (mBase != null ? mBase.checkLevel() : true));
+        }
+        return mLink;
+    }
+
+    public String label()
+    {
+        return linkReference().label;
+    }
+
+    @Override
+    public void makeHDF(HDF data, String base)
+    {
+        LinkReference linkRef = linkReference();
+        if (linkRef.kind != null) {
+            // if they have a better suggestion about "kind" use that.
+            // do this before super.makeHDF() so it picks it up
+            setKind(linkRef.kind);
+        }
+
+        super.makeHDF(data, base);
+
+        data.setValue(base + ".label", linkRef.label);
+        if (linkRef.href != null) {
+            data.setValue(base + ".href", linkRef.href);
+        }
+    }
+
+    public boolean checkLevel() {
+        return linkReference().checkLevel();
+    }
+
+    public static void makeHDF(HDF data, String base, SeeTagInfo[] tags)
+    {
+        int j=0;
+        for (SeeTagInfo tag: tags) {
+            if (tag.mBase.checkLevel() && tag.checkLevel()) {
+                tag.makeHDF(data, base + "." + j);
+                j++;
+            }
+        }
+    }
+}
diff --git a/build/tools/droiddoc/src/SinceTagger.java b/build/tools/droiddoc/src/SinceTagger.java
new file mode 100644 (file)
index 0000000..a1bce55
--- /dev/null
@@ -0,0 +1,237 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+
+import com.android.apicheck.ApiCheck;
+import com.android.apicheck.ApiInfo;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Collections;
+
+import org.clearsilver.HDF;
+
+/**
+ * Applies version information to the DroidDoc class model from apicheck XML
+ * files. Sample usage:
+ * <pre>
+ *   ClassInfo[] classInfos = ...
+ *
+ *   SinceTagger sinceTagger = new SinceTagger()
+ *   sinceTagger.addVersion("frameworks/base/api/1.xml", "Android 1.0")
+ *   sinceTagger.addVersion("frameworks/base/api/2.xml", "Android 1.5")
+ *   sinceTagger.tagAll(...);
+ * </pre>
+ */
+public class SinceTagger {
+
+    private final Map<String, String> xmlToName
+            = new LinkedHashMap<String, String>();
+
+    /**
+     * Specifies the apicheck XML file and the API version it holds. Calls to
+     * this method should be called in order from oldest version to newest.
+     */
+    public void addVersion(String file, String name) {
+        xmlToName.put(file, name);
+    }
+
+    public void tagAll(ClassInfo[] classDocs) {
+        // read through the XML files in order, applying their since information
+        // to the Javadoc models
+        for (Map.Entry<String, String> versionSpec : xmlToName.entrySet()) {
+            String xmlFile = versionSpec.getKey();
+            String versionName = versionSpec.getValue();
+            ApiInfo specApi = new ApiCheck().parseApi(xmlFile);
+
+            applyVersionsFromSpec(versionName, specApi, classDocs);
+        }
+
+        if (!xmlToName.isEmpty()) {
+            warnForMissingVersions(classDocs);
+        }
+    }
+
+    /**
+     * Writes an index of the version names to {@code data}. 
+     */
+    public void writeVersionNames(HDF data) {
+        int index = 1;
+        for (String version : xmlToName.values()) {
+            data.setValue("since." + index + ".name", version);
+            index++;
+        }
+    }
+
+    /**
+     * Applies the version information to {@code classDocs} where not already
+     * present.
+     *
+     * @param versionName the version name
+     * @param specApi the spec for this version. If a symbol is in this spec, it
+     *      was present in the named version
+     * @param classDocs the doc model to update
+     */
+    private void applyVersionsFromSpec(String versionName,
+            ApiInfo specApi, ClassInfo[] classDocs) {
+        for (ClassInfo classDoc : classDocs) {
+            com.android.apicheck.PackageInfo packageSpec
+                    = specApi.getPackages().get(classDoc.containingPackage().name());
+
+            if (packageSpec == null) {
+                continue;
+            }
+
+            com.android.apicheck.ClassInfo classSpec
+                    = packageSpec.allClasses().get(classDoc.name());
+
+            if (classSpec == null) {
+                continue;
+            }
+
+            versionPackage(versionName, classDoc.containingPackage());
+            versionClass(versionName, classDoc);
+            versionConstructors(versionName, classSpec, classDoc);
+            versionFields(versionName, classSpec, classDoc);
+            versionMethods(versionName, classSpec, classDoc);
+        }
+    }
+
+    /**
+     * Applies version information to {@code doc} where not already present.
+     */
+    private void versionPackage(String versionName, PackageInfo doc) {
+        if (doc.getSince() == null) {
+            doc.setSince(versionName);
+        }
+    }
+
+    /**
+     * Applies version information to {@code doc} where not already present.
+     */
+    private void versionClass(String versionName, ClassInfo doc) {
+        if (doc.getSince() == null) {
+            doc.setSince(versionName);
+        }
+    }
+
+    /**
+     * Applies version information from {@code spec} to {@code doc} where not
+     * already present.
+     */
+    private void versionConstructors(String versionName,
+            com.android.apicheck.ClassInfo spec, ClassInfo doc) {
+        for (MethodInfo constructor : doc.constructors()) {
+            if (constructor.getSince() == null
+                    && spec.allConstructors().containsKey(constructor.getHashableName())) {
+                constructor.setSince(versionName);
+            }
+        }
+    }
+
+    /**
+     * Applies version information from {@code spec} to {@code doc} where not
+     * already present.
+     */
+    private void versionFields(String versionName,
+            com.android.apicheck.ClassInfo spec, ClassInfo doc) {
+        for (FieldInfo field : doc.fields()) {
+            if (field.getSince() == null
+                    && spec.allFields().containsKey(field.name())) {
+                field.setSince(versionName);
+            }
+        }
+    }
+
+    /**
+     * Applies version information from {@code spec} to {@code doc} where not
+     * already present.
+     */
+    private void versionMethods(String versionName,
+            com.android.apicheck.ClassInfo spec, ClassInfo doc) {
+        for (MethodInfo method : doc.methods()) {
+            if (method.getSince() != null) {
+                continue;
+            }
+
+            for (com.android.apicheck.ClassInfo superclass : spec.hierarchy()) {
+                if (superclass.allMethods().containsKey(method.getHashableName())) {
+                    method.setSince(versionName);
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Warns if any symbols are missing version information. When configured
+     * properly, this will yield zero warnings because {@code apicheck}
+     * guarantees that all symbols are present in the most recent API.
+     */
+    private void warnForMissingVersions(ClassInfo[] classDocs) {
+        for (ClassInfo claz : classDocs) {
+            if (!checkLevelRecursive(claz)) {
+                continue;
+            }
+
+            if (claz.getSince() == null) {
+                Errors.error(Errors.NO_SINCE_DATA, claz.position(),
+                        "XML missing class " + claz.qualifiedName());
+            }
+            
+            for (FieldInfo field : missingVersions(claz.fields())) {
+                Errors.error(Errors.NO_SINCE_DATA, field.position(),
+                        "XML missing field " + claz.qualifiedName()
+                                + "#" + field.name());
+            }
+
+            for (MethodInfo constructor : missingVersions(claz.constructors())) {
+                Errors.error(Errors.NO_SINCE_DATA, constructor.position(),
+                        "XML missing constructor " + claz.qualifiedName()
+                                + "#" + constructor.getHashableName());
+            }
+
+            for (MethodInfo method : missingVersions(claz.methods())) {
+                Errors.error(Errors.NO_SINCE_DATA, method.position(),
+                        "XML missing method " + claz.qualifiedName()
+                                + "#" + method.getHashableName());
+            }
+        }
+    }
+
+    /**
+     * Returns the DocInfos in {@code all} that are documented but do not have
+     * since tags.
+     */
+    private <T extends MemberInfo> Iterable<T> missingVersions(T[] all) {
+        List<T> result = Collections.emptyList();
+        for (T t : all) {
+            // if this member has version info or isn't documented, skip it
+            if (t.getSince() != null
+                    || t.isHidden()
+                    || !checkLevelRecursive(t.realContainingClass())) {
+                continue;
+            }
+
+            if (result.isEmpty()) {
+                result = new ArrayList<T>(); // lazily construct a mutable list
+            }
+            result.add(t);
+        }
+        return result;
+    }
+
+    /**
+     * Returns true if {@code claz} and all containing classes are documented.
+     * The result may be used to filter out members that exist in the API
+     * data structure but aren't a part of the API.
+     */
+    private boolean checkLevelRecursive(ClassInfo claz) {
+        for (ClassInfo c = claz; c != null; c = c.containingClass()) {
+            if (!c.checkLevel()) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/build/tools/droiddoc/src/Sorter.java b/build/tools/droiddoc/src/Sorter.java
new file mode 100644 (file)
index 0000000..92039d4
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Sorter implements Comparable
+{
+    public String label;
+    public Object data;
+
+    public Sorter(String l, Object d)
+    {
+        label = l;
+        data = d;
+    }
+
+    public int compareTo(Object other)
+    {
+        return label.compareToIgnoreCase(((Sorter)other).label);
+    }
+}
diff --git a/build/tools/droiddoc/src/SourcePositionInfo.java b/build/tools/droiddoc/src/SourcePositionInfo.java
new file mode 100644 (file)
index 0000000..ac605ec
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class SourcePositionInfo implements Comparable
+{
+    public SourcePositionInfo() {
+        this.file = "<unknown>";
+        this.line = 0;
+        this.column = 0;
+    }
+
+    public SourcePositionInfo(String file, int line, int column)
+    {
+        this.file = file;
+        this.line = line;
+        this.column = column;
+    }
+
+    public SourcePositionInfo(SourcePositionInfo that)
+    {
+        this.file = that.file;
+        this.line = that.line;
+        this.column = that.column;
+    }
+
+    /**
+     * Given this position and str which occurs at that position, as well as str an index into str,
+     * find the SourcePositionInfo.
+     *
+     * @throw StringIndexOutOfBoundsException if index &gt; str.length()
+     */
+    public static SourcePositionInfo add(SourcePositionInfo that, String str, int index)
+    {
+        if (that == null) {
+            return null;
+        }
+        int line = that.line;
+        char prev = 0;
+        for (int i=0; i<index; i++) {
+            char c = str.charAt(i);
+            if (c == '\r' || (c == '\n' && prev != '\r')) {
+                line++;
+            }
+            prev = c;
+        }
+        return new SourcePositionInfo(that.file, line, 0);
+    }
+
+    public static SourcePositionInfo findBeginning(SourcePositionInfo that, String str)
+    {
+        if (that == null) {
+            return null;
+        }
+        int line = that.line-1; // -1 because, well, it seems to work
+        int prev = 0;
+        for (int i=str.length()-1; i>=0; i--) {
+            char c = str.charAt(i);
+            if ((c == '\r' && prev != '\n') || (c == '\n')) {
+                line--;
+            }
+            prev = c;
+        }
+        return new SourcePositionInfo(that.file, line, 0);
+    }
+
+    @Override
+    public String toString()
+    {
+        return file + ':' + line;
+    }
+
+    public int compareTo(Object o) {
+        SourcePositionInfo that = (SourcePositionInfo)o;
+        int r = this.file.compareTo(that.file);
+        if (r != 0) return r;
+        return this.line - that.line;
+    }
+
+    public String file;
+    public int line;
+    public int column;
+}
diff --git a/build/tools/droiddoc/src/Stubs.java b/build/tools/droiddoc/src/Stubs.java
new file mode 100644 (file)
index 0000000..b988ef5
--- /dev/null
@@ -0,0 +1,999 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.Comparator;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
+
+public class Stubs {
+    private static HashSet<ClassInfo> notStrippable;
+    public static void writeStubs(String stubsDir, Boolean writeXML, String xmlFile,
+            HashSet<String> stubPackages) {
+        // figure out which classes we need
+        notStrippable = new HashSet();
+        ClassInfo[] all = Converter.allClasses();
+        File  xml = new File(xmlFile);
+        xml.getParentFile().mkdirs();
+        PrintStream xmlWriter = null;
+        if (writeXML) {
+            try {
+                xmlWriter = new PrintStream(xml);
+            } catch (FileNotFoundException e) {
+                Errors.error(Errors.IO_ERROR, new SourcePositionInfo(xmlFile, 0, 0),
+                        "Cannot open file for write.");
+            }
+        }
+        // If a class is public or protected, not hidden, and marked as included,
+        // then we can't strip it
+        for (ClassInfo cl: all) {
+            if (cl.checkLevel() && cl.isIncluded()) {
+                cantStripThis(cl, notStrippable, "0:0");
+            }
+        }
+
+        // complain about anything that looks includeable but is not supposed to
+        // be written, e.g. hidden things
+        for (ClassInfo cl: notStrippable) {
+            if (!cl.isHidden()) {
+                MethodInfo[] methods = cl.selfMethods();
+                for (MethodInfo m: methods) {
+                    if (m.isHidden()) {
+                        Errors.error(Errors.UNAVAILABLE_SYMBOL,
+                                m.position(), "Reference to hidden method "
+                                + m.name());
+                    } else if (m.isDeprecated()) {
+                        // don't bother reporting deprecated methods
+                        // unless they are public
+                        Errors.error(Errors.DEPRECATED,
+                                m.position(), "Method "
+                                + cl.qualifiedName() + "." + m.name()
+                                + " is deprecated");
+                    }
+
+                    ClassInfo returnClass = m.returnType().asClassInfo();
+                    if (returnClass != null && returnClass.isHidden()) {
+                        Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(),
+                                "Method " + cl.qualifiedName() + "." + m.name()
+                                + " returns unavailable type " + returnClass.name());
+                    }
+
+                    ParameterInfo[] params = m.parameters();
+                    for (ParameterInfo p: params) {
+                        TypeInfo t = p.type();
+                        if (!t.isPrimitive()) {
+                            if (t.asClassInfo().isHidden()) {
+                                Errors.error(Errors.UNAVAILABLE_SYMBOL,
+                                        m.position(), "Parameter of hidden type "
+                                        + t.fullName() + " in "
+                                        + cl.qualifiedName() + "." + m.name() + "()");
+                            }
+                        }
+                    }
+                }
+
+                // annotations are handled like methods
+                methods = cl.annotationElements();
+                for (MethodInfo m: methods) {
+                    if (m.isHidden()) {
+                        Errors.error(Errors.UNAVAILABLE_SYMBOL,
+                                m.position(), "Reference to hidden annotation "
+                                + m.name());
+                    }
+
+                    ClassInfo returnClass = m.returnType().asClassInfo();
+                    if (returnClass != null && returnClass.isHidden()) {
+                        Errors.error(Errors.UNAVAILABLE_SYMBOL,
+                                m.position(), "Annotation '" + m.name()
+                                + "' returns unavailable type " + returnClass.name());
+                    }
+
+                    ParameterInfo[] params = m.parameters();
+                    for (ParameterInfo p: params) {
+                        TypeInfo t = p.type();
+                        if (!t.isPrimitive()) {
+                            if (t.asClassInfo().isHidden()) {
+                                Errors.error(Errors.UNAVAILABLE_SYMBOL,
+                                        p.position(), "Reference to unavailable annotation class "
+                                        + t.fullName());
+                            }
+                        }
+                    }
+                }
+            } else if (cl.isDeprecated()) {
+                // not hidden, but deprecated
+                Errors.error(Errors.DEPRECATED,
+                        cl.position(), "Class " + cl.qualifiedName()
+                        + " is deprecated");
+            }
+        }
+
+        // write out the stubs
+        HashMap<PackageInfo, List<ClassInfo>> packages = new HashMap<PackageInfo, List<ClassInfo>>();
+        for (ClassInfo cl: notStrippable) {
+            if (!cl.isDocOnly()) {
+                if (stubPackages == null || stubPackages.contains(cl.containingPackage().name())) {
+                    writeClassFile(stubsDir, cl);
+                    if (packages.containsKey(cl.containingPackage())) {
+                        packages.get(cl.containingPackage()).add(cl);
+                    } else {
+                        ArrayList<ClassInfo> classes = new ArrayList<ClassInfo>();
+                        classes.add(cl);
+                        packages.put(cl.containingPackage(), classes);
+                    }
+                }
+            }
+        }
+
+        // write out the XML
+        if (writeXML && xmlWriter != null) {
+            writeXML(xmlWriter, packages, notStrippable);
+        }
+
+        if (xmlWriter != null) {
+            xmlWriter.close();
+        }
+
+    }
+
+    public static void cantStripThis(ClassInfo cl, HashSet<ClassInfo> notStrippable, String why) {
+
+      if (!notStrippable.add(cl)) {
+        // slight optimization: if it already contains cl, it already contains
+        // all of cl's parents
+          return;
+      }
+      cl.setReasonIncluded(why);
+
+      // cant strip annotations
+      /*if (cl.annotations() != null){
+          for (AnnotationInstanceInfo ai : cl.annotations()){
+              if (ai.type() != null){
+                  cantStripThis(ai.type(), notStrippable, "1:" + cl.qualifiedName());
+              }
+          }
+      }*/
+      // cant strip any public fields or their generics
+      if (cl.allSelfFields() != null){
+          for (FieldInfo fInfo : cl.allSelfFields()){
+              if (fInfo.type() != null){
+                  if (fInfo.type().asClassInfo() != null){
+                      cantStripThis(fInfo.type().asClassInfo(), notStrippable,
+                          "2:" + cl.qualifiedName());
+                  }
+                  if (fInfo.type().typeArguments() != null){
+                      for (TypeInfo tTypeInfo : fInfo.type().typeArguments()){
+                          if (tTypeInfo.asClassInfo() != null){
+                              cantStripThis(tTypeInfo.asClassInfo(), notStrippable,
+                                  "3:" + cl.qualifiedName());
+                          }
+                      }
+                  }
+              }
+          }
+      }
+      //cant strip any of the type's generics
+      if (cl.asTypeInfo() != null){
+          if (cl.asTypeInfo().typeArguments() != null){
+              for (TypeInfo tInfo : cl.asTypeInfo().typeArguments()){
+                  if (tInfo.asClassInfo() != null){
+                      cantStripThis(tInfo.asClassInfo(), notStrippable, "4:" + cl.qualifiedName());
+                  }
+              }
+          }
+      }
+      //cant strip any of the annotation elements
+      //cantStripThis(cl.annotationElements(), notStrippable);
+      // take care of methods
+      cantStripThis(cl.allSelfMethods(), notStrippable);
+      cantStripThis(cl.allConstructors(), notStrippable);
+      // blow the outer class open if this is an inner class
+      if(cl.containingClass() != null){
+          cantStripThis(cl.containingClass(), notStrippable, "5:" + cl.qualifiedName());
+      }
+      // blow open super class and interfaces
+     ClassInfo supr = cl.realSuperclass();
+      if (supr != null) {
+          if (supr.isHidden()) {
+              // cl is a public class declared as extending a hidden superclass.
+              // this is not a desired practice but it's happened, so we deal
+              // with it by stripping off the superclass relation for purposes of
+              // generating the doc & stub information, and proceeding normally.
+              cl.init(cl.asTypeInfo(), cl.realInterfaces(), cl.realInterfaceTypes(),
+                      cl.innerClasses(), cl.allConstructors(), cl.allSelfMethods(),
+                      cl.annotationElements(), cl.allSelfFields(), cl.enumConstants(),
+                      cl.containingPackage(), cl.containingClass(),
+                      null, null, cl.annotations());
+              Errors.error(Errors.HIDDEN_SUPERCLASS,
+                      cl.position(), "Public class " + cl.qualifiedName()
+                      + " stripped of unavailable superclass "
+                      + supr.qualifiedName());
+          } else {
+              cantStripThis(supr, notStrippable, "6:" + cl.realSuperclass().name()
+                      + cl.qualifiedName());
+          }
+      }
+    }
+
+    private static void cantStripThis(MethodInfo[] mInfos , HashSet<ClassInfo> notStrippable) {
+      //for each method, blow open the parameters, throws and return types.  also blow open their generics
+      if (mInfos != null){
+          for (MethodInfo mInfo : mInfos){
+              if (mInfo.getTypeParameters() != null){
+                  for (TypeInfo tInfo : mInfo.getTypeParameters()){
+                      if (tInfo.asClassInfo() != null){
+                          cantStripThis(tInfo.asClassInfo(), notStrippable, "8:" +
+                                        mInfo.realContainingClass().qualifiedName() + ":" +
+                                        mInfo.name());
+                      }
+                  }
+              }
+              if (mInfo.parameters() != null){
+                  for (ParameterInfo pInfo : mInfo.parameters()){
+                      if (pInfo.type() != null && pInfo.type().asClassInfo() != null){
+                          cantStripThis(pInfo.type().asClassInfo(), notStrippable,
+                                        "9:"+  mInfo.realContainingClass().qualifiedName()
+                                        + ":" + mInfo.name());
+                          if (pInfo.type().typeArguments() != null){
+                              for (TypeInfo tInfoType : pInfo.type().typeArguments()){
+                                  if (tInfoType.asClassInfo() != null){
+                                      ClassInfo tcl = tInfoType.asClassInfo();
+                                      if (tcl.isHidden()) {
+                                          Errors.error(Errors.UNAVAILABLE_SYMBOL, mInfo.position(),
+                                                  "Parameter of hidden type "
+                                                  + tInfoType.fullName() + " in "
+                                                  + mInfo.containingClass().qualifiedName()
+                                                  + '.' + mInfo.name() + "()");
+                                      } else {
+                                          cantStripThis(tcl, notStrippable,
+                                                  "10:" +
+                                                  mInfo.realContainingClass().qualifiedName() + ":" +
+                                                  mInfo.name());
+                                      }
+                                  }
+                              }
+                          }
+                      }
+                  }
+              }
+              for (ClassInfo thrown : mInfo.thrownExceptions()){
+                  cantStripThis(thrown, notStrippable, "11:" +
+                                mInfo.realContainingClass().qualifiedName()
+                                +":" + mInfo.name());
+              }
+              if (mInfo.returnType() != null && mInfo.returnType().asClassInfo() != null){
+                  cantStripThis(mInfo.returnType().asClassInfo(), notStrippable,
+                                "12:" + mInfo.realContainingClass().qualifiedName() +
+                                ":" + mInfo.name());
+                  if (mInfo.returnType().typeArguments() != null){
+                      for (TypeInfo tyInfo: mInfo.returnType().typeArguments() ){
+                          if (tyInfo.asClassInfo() != null){
+                              cantStripThis(tyInfo.asClassInfo(), notStrippable,
+                                            "13:" +
+                                            mInfo.realContainingClass().qualifiedName()
+                                            + ":" + mInfo.name());
+                          }
+                      }
+                  }
+              }
+          }
+      }
+    }
+
+    static String javaFileName(ClassInfo cl) {
+        String dir = "";
+        PackageInfo pkg = cl.containingPackage();
+        if (pkg != null) {
+            dir = pkg.name();
+            dir = dir.replace('.', '/') + '/';
+        }
+        return dir + cl.name() + ".java";
+    }
+
+    static void writeClassFile(String stubsDir, ClassInfo cl) {
+        // inner classes are written by their containing class
+        if (cl.containingClass() != null) {
+            return;
+        }
+
+        // Work around the bogus "Array" class we invent for
+        // Arrays.copyOf's Class<? extends T[]> newType parameter. (http://b/2715505)
+        if (cl.containingPackage() != null && cl.containingPackage().name().equals("")) {
+            return;
+        }
+
+        String filename = stubsDir + '/' + javaFileName(cl);
+        File file = new File(filename);
+        ClearPage.ensureDirectory(file);
+
+        PrintStream stream = null;
+        try {
+            stream = new PrintStream(file);
+            writeClassFile(stream, cl);
+        }
+        catch (FileNotFoundException e) {
+            System.err.println("error writing file: " + filename);
+        }
+        finally {
+            if (stream != null) {
+                stream.close();
+            }
+        }
+    }
+
+    static void writeClassFile(PrintStream stream, ClassInfo cl) {
+        PackageInfo pkg = cl.containingPackage();
+        if (pkg != null) {
+            stream.println("package " + pkg.name() + ";");
+        }
+        writeClass(stream, cl);
+    }
+
+    static void writeClass(PrintStream stream, ClassInfo cl) {
+        writeAnnotations(stream, cl.annotations());
+
+        stream.print(DroidDoc.scope(cl) + " ");
+        if (cl.isAbstract() && !cl.isAnnotation() && !cl.isInterface()) {
+            stream.print("abstract ");
+        }
+        if (cl.isStatic()){
+            stream.print("static ");
+        }
+        if (cl.isFinal() && !cl.isEnum()) {
+            stream.print("final ");
+        }
+        if (false) {
+            stream.print("strictfp ");
+        }
+
+        HashSet<String> classDeclTypeVars = new HashSet();
+        String leafName = cl.asTypeInfo().fullName(classDeclTypeVars);
+        int bracket = leafName.indexOf('<');
+        if (bracket < 0) bracket = leafName.length() - 1;
+        int period = leafName.lastIndexOf('.', bracket);
+        if (period < 0) period = -1;
+        leafName = leafName.substring(period+1);
+
+        String kind = cl.kind();
+        stream.println(kind + " " + leafName);
+
+        TypeInfo base = cl.superclassType();
+
+        if (!"enum".equals(kind)) {
+            if (base != null && !"java.lang.Object".equals(base.qualifiedTypeName())) {
+                stream.println("  extends " + base.fullName(classDeclTypeVars));
+            }
+        }
+
+        TypeInfo[] interfaces = cl.realInterfaceTypes();
+        List<TypeInfo> usedInterfaces = new ArrayList<TypeInfo>();
+        for (TypeInfo iface : interfaces) {
+            if (notStrippable.contains(iface.asClassInfo())
+                    && !iface.asClassInfo().isDocOnly()) {
+                usedInterfaces.add(iface);
+            }
+        }
+        if (usedInterfaces.size() > 0 && !cl.isAnnotation()) {
+            // can java annotations extend other ones?
+            if (cl.isInterface() || cl.isAnnotation()) {
+                stream.print("  extends ");
+            } else {
+                stream.print("  implements ");
+            }
+            String comma = "";
+            for (TypeInfo iface: usedInterfaces) {
+                stream.print(comma + iface.fullName(classDeclTypeVars));
+                comma = ", ";
+            }
+            stream.println();
+        }
+
+        stream.println("{");
+
+        FieldInfo[] enumConstants = cl.enumConstants();
+        int N = enumConstants.length;
+        for (int i=0; i<N; i++) {
+            FieldInfo field = enumConstants[i];
+            if (!field.constantLiteralValue().equals("null")){
+            stream.println(field.name() + "(" + field.constantLiteralValue()
+                    + (i==N-1 ? ");" : "),"));
+            }else{
+              stream.println(field.name() + "(" + (i==N-1 ? ");" : "),"));
+            }
+        }
+
+        for (ClassInfo inner: cl.getRealInnerClasses()) {
+            if (notStrippable.contains(inner)
+                    && !inner.isDocOnly()){
+                writeClass(stream, inner);
+            }
+        }
+
+
+        for (MethodInfo method: cl.constructors()) {
+            if (!method.isDocOnly()) {
+                writeMethod(stream, method, true);
+            }
+        }
+
+        boolean fieldNeedsInitialization = false;
+        boolean staticFieldNeedsInitialization = false;
+        for (FieldInfo field: cl.allSelfFields()) {
+            if (!field.isDocOnly()) {
+                if (!field.isStatic() && field.isFinal() && !fieldIsInitialized(field)) {
+                    fieldNeedsInitialization = true;
+                }
+                if (field.isStatic() && field.isFinal() && !fieldIsInitialized(field)) {
+                    staticFieldNeedsInitialization = true;
+                }
+            }
+        }
+
+        // The compiler includes a default public constructor that calls the super classes
+        // default constructor in the case where there are no written constructors.
+        // So, if we hide all the constructors, java may put in a constructor
+        // that calls a nonexistent super class constructor.  So, if there are no constructors,
+        // and the super class doesn't have a default constructor, write in a private constructor
+        // that works.  TODO -- we generate this as protected, but we really should generate
+        // it as private unless it also exists in the real code.
+        if ((cl.constructors().length == 0 && (cl.getNonWrittenConstructors().length != 0
+                    || fieldNeedsInitialization))
+                && !cl.isAnnotation()
+                && !cl.isInterface()
+                && !cl.isEnum() ) {
+            //Errors.error(Errors.HIDDEN_CONSTRUCTOR,
+            //             cl.position(), "No constructors " +
+            //            "found and superclass has no parameterless constructor.  A constructor " +
+            //            "that calls an appropriate superclass constructor " +
+            //            "was automatically written to stubs.\n");
+            stream.println(cl.leafName()
+                    + "() { " + superCtorCall(cl,null)
+                    + "throw new" + " RuntimeException(\"Stub!\"); }");
+        }
+
+        for (MethodInfo method: cl.allSelfMethods()) {
+            if (cl.isEnum()) {
+                if (("values".equals(method.name())
+                            && "()".equals(method.signature()))
+                    || ("valueOf".equals(method.name())
+                            && "(java.lang.String)".equals(method.signature()))) {
+                    // skip these two methods on enums, because they're synthetic,
+                    // although for some reason javadoc doesn't mark them as synthetic,
+                    // maybe because they still want them documented
+                    continue;
+                }
+            }
+            if (!method.isDocOnly()) {
+                writeMethod(stream, method, false);
+            }
+        }
+        //Write all methods that are hidden, but override abstract methods or interface methods.
+        //These can't be hidden.
+        for (MethodInfo method : cl.getHiddenMethods()){
+            MethodInfo overriddenMethod = method.findRealOverriddenMethod(method.name(), method.signature(), notStrippable);
+            ClassInfo classContainingMethod = method.findRealOverriddenClass(method.name(),
+                                                                             method.signature());
+            if (overriddenMethod != null && !overriddenMethod.isHidden()
+                && !overriddenMethod.isDocOnly() &&
+                (overriddenMethod.isAbstract() ||
+                overriddenMethod.containingClass().isInterface())) {
+                method.setReason("1:" + classContainingMethod.qualifiedName());
+                cl.addMethod(method);
+                writeMethod(stream, method, false);
+            }
+        }
+
+        for (MethodInfo element: cl.annotationElements()) {
+            if (!element.isDocOnly()) {
+                writeAnnotationElement(stream, element);
+            }
+        }
+
+        for (FieldInfo field: cl.allSelfFields()) {
+            if (!field.isDocOnly()) {
+                writeField(stream, field);
+            }
+        }
+
+        if (staticFieldNeedsInitialization) {
+            stream.print("static { ");
+            for (FieldInfo field: cl.allSelfFields()) {
+                if (!field.isDocOnly() && field.isStatic() && field.isFinal()
+                        && !fieldIsInitialized(field) && field.constantValue() == null) {
+                    stream.print(field.name() + " = " + field.type().defaultValue()
+                            + "; ");
+                }
+            }
+            stream.println("}");
+        }
+
+        stream.println("}");
+    }
+
+
+    static void writeMethod(PrintStream stream, MethodInfo method, boolean isConstructor) {
+        String comma;
+
+        stream.print(DroidDoc.scope(method) + " ");
+        if (method.isStatic()) {
+            stream.print("static ");
+        }
+        if (method.isFinal()) {
+            stream.print("final ");
+        }
+        if (method.isAbstract()) {
+            stream.print("abstract ");
+        }
+        if (method.isSynchronized()) {
+            stream.print("synchronized ");
+        }
+        if (method.isNative()) {
+            stream.print("native ");
+        }
+        if (false /*method.isStictFP()*/) {
+            stream.print("strictfp ");
+        }
+
+        stream.print(method.typeArgumentsName(new HashSet()) + " ");
+
+        if (!isConstructor) {
+            stream.print(method.returnType().fullName(method.typeVariables()) + " ");
+        }
+        String n = method.name();
+        int pos = n.lastIndexOf('.');
+        if (pos >= 0) {
+            n = n.substring(pos + 1);
+        }
+        stream.print(n + "(");
+        comma = "";
+        int count = 1;
+        int size = method.parameters().length;
+        for (ParameterInfo param: method.parameters()) {
+            stream.print(comma + fullParameterTypeName(method, param.type(), count == size)
+                    + " " + param.name());
+            comma = ", ";
+            count++;
+        }
+        stream.print(")");
+
+        comma = "";
+        if (method.thrownExceptions().length > 0) {
+            stream.print(" throws ");
+            for (ClassInfo thrown: method.thrownExceptions()) {
+                stream.print(comma + thrown.qualifiedName());
+                comma = ", ";
+            }
+        }
+        if (method.isAbstract() || method.isNative() || method.containingClass().isInterface()) {
+            stream.println(";");
+        } else {
+            stream.print(" { ");
+            if (isConstructor) {
+                stream.print(superCtorCall(method.containingClass(), method.thrownExceptions()));
+            }
+            stream.println("throw new RuntimeException(\"Stub!\"); }");
+        }
+    }
+
+    static void writeField(PrintStream stream, FieldInfo field) {
+        stream.print(DroidDoc.scope(field) + " ");
+        if (field.isStatic()) {
+            stream.print("static ");
+        }
+        if (field.isFinal()) {
+            stream.print("final ");
+        }
+        if (field.isTransient()) {
+            stream.print("transient ");
+        }
+        if (field.isVolatile()) {
+            stream.print("volatile ");
+        }
+
+        stream.print(field.type().fullName());
+        stream.print(" ");
+        stream.print(field.name());
+
+        if (fieldIsInitialized(field)) {
+            stream.print(" = " + field.constantLiteralValue());
+        }
+
+        stream.println(";");
+    }
+
+    static boolean fieldIsInitialized(FieldInfo field) {
+        return (field.isFinal() && field.constantValue() != null)
+                || !field.type().dimension().equals("")
+                || field.containingClass().isInterface();
+    }
+
+    // Returns 'true' if the method is an @Override of a visible parent
+    // method implementation, and thus does not affect the API.
+    static boolean methodIsOverride(MethodInfo mi) {
+        // Abstract/static/final methods are always listed in the API description
+        if (mi.isAbstract() || mi.isStatic() || mi.isFinal()) {
+            return false;
+        }
+
+        // Find any relevant ancestor declaration and inspect it
+        MethodInfo om = mi.findSuperclassImplementation(notStrippable);
+        if (om != null) {
+            // Visibility mismatch is an API change, so check for it
+            if (mi.mIsPrivate == om.mIsPrivate
+                    && mi.mIsPublic == om.mIsPublic
+                    && mi.mIsProtected == om.mIsProtected) {
+                // Look only for overrides of an ancestor class implementation,
+                // not of e.g. an abstract or interface method declaration
+                if (!om.isAbstract()) {
+                    // If the parent is hidden, we can't rely on it to provide
+                    // the API
+                    if (!om.isHidden()) {
+                        // If the only "override" turns out to be in our own class
+                        // (which sometimes happens in concrete subclasses of
+                        // abstract base classes), it's not really an override
+                        if (!mi.mContainingClass.equals(om.mContainingClass)) {
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    static boolean canCallMethod(ClassInfo from, MethodInfo m) {
+        if (m.isPublic() || m.isProtected()) {
+            return true;
+        }
+        if (m.isPackagePrivate()) {
+            String fromPkg = from.containingPackage().name();
+            String pkg = m.containingClass().containingPackage().name();
+            if (fromPkg.equals(pkg)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // call a constructor, any constructor on this class's superclass.
+    static String superCtorCall(ClassInfo cl, ClassInfo[] thrownExceptions) {
+        ClassInfo base = cl.realSuperclass();
+        if (base == null) {
+            return "";
+        }
+        HashSet<String> exceptionNames = new HashSet<String>();
+        if (thrownExceptions != null ){
+            for (ClassInfo thrown : thrownExceptions){
+              exceptionNames.add(thrown.name());
+            }
+        }
+        MethodInfo[] ctors = base.constructors();
+        MethodInfo ctor = null;
+        //bad exception indicates that the exceptions thrown by the super constructor
+        //are incompatible with the constructor we're using for the sub class.
+        Boolean badException = false;
+        for (MethodInfo m: ctors) {
+            if (canCallMethod(cl, m)) {
+                if (m.thrownExceptions() != null){
+                    for (ClassInfo thrown : m.thrownExceptions()){
+                        if (!exceptionNames.contains(thrown.name())){
+                            badException = true;
+                        }
+                    }
+                }
+                if (badException){
+                  badException = false;
+                  continue;
+                }
+                // if it has no args, we're done
+                if (m.parameters().length == 0) {
+                    return "";
+                }
+                ctor = m;
+            }
+        }
+        if (ctor != null) {
+            String result = "";
+            result+= "super(";
+            ParameterInfo[] params = ctor.parameters();
+            int N = params.length;
+            for (int i=0; i<N; i++) {
+                TypeInfo t = params[i].type();
+                if (t.isPrimitive() && t.dimension().equals("")) {
+                    String n = t.simpleTypeName();
+                    if (("byte".equals(n)
+                            || "short".equals(n)
+                            || "int".equals(n)
+                            || "long".equals(n)
+                            || "float".equals(n)
+                            || "double".equals(n)) && t.dimension().equals("")) {
+                        result += "0";
+                    }
+                    else if ("char".equals(n)) {
+                        result += "'\\0'";
+                    }
+                    else if ("boolean".equals(n)) {
+                        result += "false";
+                    }
+                    else {
+                        result += "<<unknown-" + n + ">>";
+                    }
+                } else {
+                    //put null in each super class method.  Cast null to the correct type
+                    //to avoid collisions with other constructors.  If the type is generic
+                    //don't cast it
+                    result += (!t.isTypeVariable() ? "(" + t.qualifiedTypeName() + t.dimension() +
+                              ")" : "") + "null";
+                }
+                if (i != N-1) {
+                    result += ",";
+                }
+            }
+            result += "); ";
+            return result;
+        } else {
+            return "";
+        }
+    }
+
+    static void writeAnnotations(PrintStream stream, AnnotationInstanceInfo[] annotations) {
+        for (AnnotationInstanceInfo ann: annotations) {
+            if (!ann.type().isHidden()) {
+                stream.println(ann.toString());
+            }
+        }
+    }
+
+    static void writeAnnotationElement(PrintStream stream, MethodInfo ann) {
+        stream.print(ann.returnType().fullName());
+        stream.print(" ");
+        stream.print(ann.name());
+        stream.print("()");
+        AnnotationValueInfo def = ann.defaultAnnotationElementValue();
+        if (def != null) {
+            stream.print(" default ");
+            stream.print(def.valueString());
+        }
+        stream.println(";");
+    }
+
+    static void writeXML(PrintStream xmlWriter, HashMap<PackageInfo, List<ClassInfo>> allClasses,
+                         HashSet notStrippable) {
+        // extract the set of packages, sort them by name, and write them out in that order
+        Set<PackageInfo> allClassKeys = allClasses.keySet();
+        PackageInfo[] allPackages = allClassKeys.toArray(new PackageInfo[allClassKeys.size()]);
+        Arrays.sort(allPackages, PackageInfo.comparator);
+
+        xmlWriter.println("<api>");
+        for (PackageInfo pack : allPackages) {
+            writePackageXML(xmlWriter, pack, allClasses.get(pack), notStrippable);
+        }
+        xmlWriter.println("</api>");
+    }
+
+    static void writePackageXML(PrintStream xmlWriter, PackageInfo pack, List<ClassInfo> classList,
+                                HashSet notStrippable) {
+        ClassInfo[] classes = classList.toArray(new ClassInfo[classList.size()]);
+        Arrays.sort(classes, ClassInfo.comparator);
+        // Work around the bogus "Array" class we invent for
+        // Arrays.copyOf's Class<? extends T[]> newType parameter. (http://b/2715505)
+        if (pack.name().equals("")) {
+            return;
+        }
+        xmlWriter.println("<package name=\"" + pack.name() + "\"\n"
+                //+ " source=\"" + pack.position() + "\"\n"
+                + ">");
+        for (ClassInfo cl : classes) {
+            writeClassXML(xmlWriter, cl, notStrippable);
+        }
+        xmlWriter.println("</package>");
+
+
+    }
+
+    static void writeClassXML(PrintStream xmlWriter, ClassInfo cl, HashSet notStrippable) {
+        String scope = DroidDoc.scope(cl);
+        String deprecatedString = "";
+        String declString = (cl.isInterface()) ? "interface" : "class";
+        if (cl.isDeprecated()) {
+            deprecatedString = "deprecated";
+        } else {
+            deprecatedString = "not deprecated";
+        }
+        xmlWriter.println("<" + declString + " name=\"" + cl.name() + "\"");
+        if (!cl.isInterface() && !cl.qualifiedName().equals("java.lang.Object")) {
+            xmlWriter.println(" extends=\"" + ((cl.realSuperclass() == null)
+                            ? "java.lang.Object"
+                            : cl.realSuperclass().qualifiedName()) + "\"");
+        }
+        xmlWriter.println(" abstract=\"" + cl.isAbstract() + "\"\n"
+                + " static=\"" + cl.isStatic() + "\"\n"
+                + " final=\"" + cl.isFinal() + "\"\n"
+                + " deprecated=\"" + deprecatedString + "\"\n"
+                + " visibility=\"" + scope + "\"\n"
+                //+ " source=\"" + cl.position() + "\"\n"
+                + ">");
+
+        ClassInfo[] interfaces = cl.realInterfaces();
+        Arrays.sort(interfaces, ClassInfo.comparator);
+        for (ClassInfo iface : interfaces) {
+            if (notStrippable.contains(iface)) {
+                xmlWriter.println("<implements name=\"" + iface.qualifiedName() + "\">");
+                xmlWriter.println("</implements>");
+            }
+        }
+
+        MethodInfo[] constructors = cl.constructors();
+        Arrays.sort(constructors, MethodInfo.comparator);
+        for (MethodInfo mi : constructors) {
+            writeConstructorXML(xmlWriter, mi);
+        }
+
+        MethodInfo[] methods = cl.allSelfMethods();
+        Arrays.sort(methods, MethodInfo.comparator);
+        for (MethodInfo mi : methods) {
+            if (!methodIsOverride(mi)) {
+                writeMethodXML(xmlWriter, mi);
+            }
+        }
+
+        FieldInfo[] fields = cl.allSelfFields();
+        Arrays.sort(fields, FieldInfo.comparator);
+        for (FieldInfo fi : fields) {
+            writeFieldXML(xmlWriter, fi);
+        }
+        xmlWriter.println("</" + declString + ">");
+
+    }
+
+    static void writeMethodXML(PrintStream xmlWriter, MethodInfo mi) {
+        String scope = DroidDoc.scope(mi);
+
+        String deprecatedString = "";
+        if (mi.isDeprecated()) {
+            deprecatedString = "deprecated";
+        } else {
+            deprecatedString = "not deprecated";
+        }
+        xmlWriter.println("<method name=\"" + mi.name() + "\"\n"
+                + ((mi.returnType() != null)
+                        ? " return=\"" + makeXMLcompliant(fullParameterTypeName(mi, mi.returnType(), false)) + "\"\n"
+                        : "")
+                + " abstract=\"" + mi.isAbstract() + "\"\n"
+                + " native=\"" + mi.isNative() + "\"\n"
+                + " synchronized=\"" + mi.isSynchronized() + "\"\n"
+                + " static=\"" + mi.isStatic() + "\"\n"
+                + " final=\"" + mi.isFinal() + "\"\n"
+                + " deprecated=\""+ deprecatedString + "\"\n"
+                + " visibility=\"" + scope + "\"\n"
+                //+ " source=\"" + mi.position() + "\"\n"
+                + ">");
+
+        // write parameters in declaration order
+        int numParameters = mi.parameters().length;
+        int count = 0;
+        for (ParameterInfo pi : mi.parameters()) {
+            count++;
+            writeParameterXML(xmlWriter, mi, pi, count == numParameters);
+        }
+
+        // but write exceptions in canonicalized order
+        ClassInfo[] exceptions = mi.thrownExceptions();
+        Arrays.sort(exceptions, ClassInfo.comparator);
+        for (ClassInfo pi : exceptions) {
+          xmlWriter.println("<exception name=\"" + pi.name() +"\" type=\"" + pi.qualifiedName()
+                            + "\">");
+          xmlWriter.println("</exception>");
+        }
+        xmlWriter.println("</method>");
+    }
+
+    static void writeConstructorXML(PrintStream xmlWriter, MethodInfo mi) {
+        String scope = DroidDoc.scope(mi);
+        String deprecatedString = "";
+        if (mi.isDeprecated()) {
+            deprecatedString = "deprecated";
+        } else {
+            deprecatedString = "not deprecated";
+        }
+        xmlWriter.println("<constructor name=\"" + mi.name() + "\"\n"
+                + " type=\"" + mi.containingClass().qualifiedName() + "\"\n"
+                + " static=\"" + mi.isStatic() + "\"\n"
+                + " final=\"" + mi.isFinal() + "\"\n"
+                + " deprecated=\"" + deprecatedString + "\"\n"
+                + " visibility=\"" + scope +"\"\n"
+                //+ " source=\"" + mi.position() + "\"\n"
+                + ">");
+
+        int numParameters = mi.parameters().length;
+        int count = 0;
+        for (ParameterInfo pi : mi.parameters()) {
+            count++;
+            writeParameterXML(xmlWriter, mi, pi, count == numParameters);
+        }
+
+        ClassInfo[] exceptions = mi.thrownExceptions();
+        Arrays.sort(exceptions, ClassInfo.comparator);
+        for (ClassInfo pi : exceptions) {
+            xmlWriter.println("<exception name=\"" + pi.name() +"\" type=\"" + pi.qualifiedName()
+                              + "\">");
+            xmlWriter.println("</exception>");
+        }
+        xmlWriter.println("</constructor>");
+  }
+
+    static void writeParameterXML(PrintStream xmlWriter, MethodInfo method,
+            ParameterInfo pi, boolean isLast) {
+        xmlWriter.println("<parameter name=\"" + pi.name() + "\" type=\"" +
+                makeXMLcompliant(fullParameterTypeName(method, pi.type(), isLast)) + "\">");
+        xmlWriter.println("</parameter>");
+    }
+
+    static void writeFieldXML(PrintStream xmlWriter, FieldInfo fi) {
+        String scope = DroidDoc.scope(fi);
+        String deprecatedString = "";
+        if (fi.isDeprecated()) {
+            deprecatedString = "deprecated";
+        } else {
+            deprecatedString = "not deprecated";
+        }
+        //need to make sure value is valid XML
+        String value  = makeXMLcompliant(fi.constantLiteralValue());
+
+        String fullTypeName = makeXMLcompliant(fi.type().qualifiedTypeName())
+                + fi.type().dimension();
+
+        xmlWriter.println("<field name=\"" + fi.name() +"\"\n"
+                          + " type=\"" + fullTypeName + "\"\n"
+                          + " transient=\"" + fi.isTransient() + "\"\n"
+                          + " volatile=\"" + fi.isVolatile() + "\"\n"
+                          + (fieldIsInitialized(fi) ? " value=\"" + value + "\"\n" : "")
+                          + " static=\"" + fi.isStatic() + "\"\n"
+                          + " final=\"" + fi.isFinal() + "\"\n"
+                          + " deprecated=\"" + deprecatedString + "\"\n"
+                          + " visibility=\"" + scope + "\"\n"
+                          //+ " source=\"" + fi.position() + "\"\n"
+                          + ">");
+        xmlWriter.println("</field>");
+    }
+
+    static String makeXMLcompliant(String s) {
+        String returnString = "";
+        returnString = s.replaceAll("&", "&amp;");
+        returnString = returnString.replaceAll("<", "&lt;");
+        returnString = returnString.replaceAll(">", "&gt;");
+        returnString = returnString.replaceAll("\"", "&quot;");
+        returnString = returnString.replaceAll("'", "&pos;");
+        return returnString;
+    }
+
+    static String fullParameterTypeName(MethodInfo method, TypeInfo type, boolean isLast) {
+        String fullTypeName = type.fullName(method.typeVariables());
+        if (isLast && method.isVarArgs()) {
+            // TODO: note that this does not attempt to handle hypothetical
+            // vararg methods whose last parameter is a list of arrays, e.g.
+            // "Object[]...".
+            fullTypeName = type.fullNameNoDimension(method.typeVariables()) + "...";
+        }
+        return fullTypeName;
+    }
+}
diff --git a/build/tools/droiddoc/src/TagInfo.java b/build/tools/droiddoc/src/TagInfo.java
new file mode 100644 (file)
index 0000000..d25c500
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+
+public class TagInfo
+{
+    private String mName;
+    private String mText;
+    private String mKind;
+    private SourcePositionInfo mPosition;
+
+    TagInfo(String n, String k, String t, SourcePositionInfo sp)
+    {
+        mName = n;
+        mText = t;
+        mKind = k;
+        mPosition = sp;
+    }
+
+    String name()
+    {
+        return mName;
+    }
+
+    String text()
+    {
+        return mText;
+    }
+
+    String kind()
+    {
+        return mKind;
+    }
+    
+    SourcePositionInfo position() {
+        return mPosition;
+    }
+
+    void setKind(String kind) {
+        mKind = kind;
+    }
+
+    public void makeHDF(HDF data, String base)
+    {
+        data.setValue(base + ".name", name());
+        data.setValue(base + ".text", text());
+        data.setValue(base + ".kind", kind());
+    }
+
+    public static void makeHDF(HDF data, String base, TagInfo[] tags)
+    {
+        makeHDF(data, base, tags, null, 0, 0);
+    }
+
+    public static void makeHDF(HDF data, String base, InheritedTags tags)
+    {
+        makeHDF(data, base, tags.tags(), tags.inherited(), 0, 0);
+    }
+
+    private static int makeHDF(HDF data, String base, TagInfo[] tags,
+                                InheritedTags inherited, int j, int depth)
+    {
+        int i;
+        int len = tags.length;
+        if (len == 0 && inherited != null) {
+            j = makeHDF(data, base, inherited.tags(), inherited.inherited(), j, depth+1);
+        } else {
+            for (i=0; i<len; i++, j++) {
+                TagInfo t = tags[i];
+                if (inherited != null && t.name().equals("@inheritDoc")) {
+                    j = makeHDF(data, base, inherited.tags(),
+                                    inherited.inherited(), j, depth+1);
+                } else {
+                    if (t.name().equals("@inheritDoc")) {
+                        Errors.error(Errors.BAD_INHERITDOC, t.mPosition,
+                                "@inheritDoc on class/method that is not inherited");
+                    }
+                    t.makeHDF(data, base + "." + j);
+                }
+            }
+        }
+        return j;
+    }
+}
+
diff --git a/build/tools/droiddoc/src/TextTagInfo.java b/build/tools/droiddoc/src/TextTagInfo.java
new file mode 100644 (file)
index 0000000..dcdfdd9
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class TextTagInfo extends TagInfo {
+    TextTagInfo(String n, String k, String t, SourcePositionInfo p) {
+        super(n, k, DroidDoc.escape(t), p);
+    }
+}
diff --git a/build/tools/droiddoc/src/ThrowsTagInfo.java b/build/tools/droiddoc/src/ThrowsTagInfo.java
new file mode 100644 (file)
index 0000000..318a57d
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+public class ThrowsTagInfo extends ParsedTagInfo
+{
+    static final Pattern PATTERN = Pattern.compile(
+                                "(\\S+)\\s+(.*)",
+                                Pattern.DOTALL);
+    private ClassInfo mException;
+
+    public ThrowsTagInfo(String name, String kind, String text,
+            ContainerInfo base, SourcePositionInfo sp)
+    {
+        super(name, kind, text, base, sp);
+
+        Matcher m = PATTERN.matcher(text);
+        if (m.matches()) {
+            setCommentText(m.group(2));
+            String className = m.group(1);
+            if (base instanceof ClassInfo) {
+                mException = ((ClassInfo)base).findClass(className);
+            }
+            if (mException == null) {
+                mException = Converter.obtainClass(className);
+            }
+        }
+    }
+
+    public ThrowsTagInfo(String name, String kind, String text,
+                            ClassInfo exception, String exceptionComment,
+                            ContainerInfo base, SourcePositionInfo sp)
+    {
+        super(name, kind, text, base, sp);
+        mException = exception;
+        setCommentText(exceptionComment);
+    }
+
+    public ClassInfo exception()
+    {
+        return mException;
+    }
+
+    public TypeInfo exceptionType()
+    {
+        if (mException != null) {
+            return mException.asTypeInfo();
+        } else {
+            return null;
+        }
+    }
+
+    public static void makeHDF(HDF data, String base, ThrowsTagInfo[] tags)
+    {
+        for (int i=0; i<tags.length; i++) {
+            TagInfo.makeHDF(data, base + '.' + i + ".comment",
+                    tags[i].commentTags());
+            if (tags[i].exceptionType() != null) {
+                tags[i].exceptionType().makeHDF(data, base + "." + i + ".type");
+            }
+        }
+    }
+
+    
+}
+
diff --git a/build/tools/droiddoc/src/TodoFile.java b/build/tools/droiddoc/src/TodoFile.java
new file mode 100644 (file)
index 0000000..ebef27e
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+import java.util.*;
+import java.io.*;
+
+public class TodoFile {
+
+    public static final String MISSING = "No description text";
+
+    public static boolean areTagsUseful(InheritedTags tags) {
+        while (tags != null) {
+            if (areTagsUseful(tags.tags())) {
+                return true;
+            }
+            tags = tags.inherited();
+        }
+        return false;
+    }
+
+    public static boolean areTagsUseful(TagInfo[] tags) {
+        for (TagInfo t: tags) {
+            if ("Text".equals(t.name()) && t.text().trim().length() != 0) {
+                return true;
+            }
+            if ("@inheritDoc".equals(t.name())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static void setHDF(HDF data, String base, SourcePositionInfo pos, String name,
+            String descr) {
+        data.setValue(base + ".pos", pos.toString());
+        data.setValue(base + ".name", name);
+        data.setValue(base + ".descr", descr);
+    }
+
+    static class PackageStats {
+        String name;
+        public int total;
+        public int errors;
+    }
+
+    public static String percent(int a, int b) {
+        return ""+Math.round((((b-a)/(float)b))*100) + "%";
+    }
+
+    public static void writeTodoFile(String filename) {
+        HDF data = DroidDoc.makeHDF();
+        DroidDoc.setPageTitle(data, "Missing Documentation");
+        TreeMap<String,PackageStats> packageStats = new TreeMap<String,PackageStats>();
+
+        ClassInfo[] classes = Converter.rootClasses();
+        Arrays.sort(classes);
+
+        int classIndex = 0;
+        
+        for (ClassInfo cl: classes) {
+            if (cl.isHidden()) {
+                continue;
+            }
+
+            String classBase = "classes." + classIndex;
+
+            String base = classBase + ".errors.";
+            int errors = 0;
+            int total = 1;
+
+            if (!areTagsUseful(cl.inlineTags())) {
+                setHDF(data, base + errors, cl.position(), "&lt;class comment&gt;", MISSING);
+                errors++;
+            }
+
+
+            for (MethodInfo m: cl.constructors()) {
+                boolean good = true;
+                total++;
+                if (m.checkLevel()) {
+                    if (!areTagsUseful(m.inlineTags())) {
+                        setHDF(data, base + errors, m.position(), m.name() + m.prettySignature(),
+                                MISSING);
+                        good = false;
+                    }
+                }
+                if (!good) {
+                    errors++;
+                }
+            }
+            
+            for (MethodInfo m: cl.selfMethods()) {
+                boolean good = true;
+                total++;
+                if (m.checkLevel()) {
+                    if (!areTagsUseful(m.inlineTags())) {
+                        setHDF(data, base + errors, m.position(), m.name() + m.prettySignature(),
+                                MISSING);
+                        good = false;
+                    }
+                }
+                if (!good) {
+                    errors++;
+                }
+            }
+            
+
+            for (FieldInfo f: cl.enumConstants()) {
+                boolean good = true;
+                total++;
+                if (f.checkLevel()) {
+                    if (!areTagsUseful(f.inlineTags())) {
+                        setHDF(data, base + errors, f.position(), f.name(), MISSING);
+                        good = false;
+                    }
+                }
+                if (!good) {
+                    errors++;
+                }
+            }
+            
+            for (FieldInfo f: cl.selfFields()) {
+                boolean good = true;
+                total++;
+                if (f.checkLevel()) {
+                    if (!areTagsUseful(f.inlineTags())) {
+                        setHDF(data, base + errors, f.position(), f.name(), MISSING);
+                        good = false;
+                    }
+                }
+                if (!good) {
+                    errors++;
+                }
+            }
+
+            if (errors > 0) {
+                data.setValue(classBase + ".qualified", cl.qualifiedName());
+                data.setValue(classBase + ".errorCount", ""+errors);
+                data.setValue(classBase + ".totalCount", ""+total);
+                data.setValue(classBase + ".percentGood", percent(errors, total));
+            }
+
+            PackageInfo pkg = cl.containingPackage();
+            String pkgName = pkg != null ? pkg.name() : "";
+            PackageStats ps = packageStats.get(pkgName);
+            if (ps == null) {
+                ps = new PackageStats();
+                ps.name = pkgName;
+                packageStats.put(pkgName, ps);
+            }
+            ps.total += total;
+            ps.errors += errors;
+
+            classIndex++;
+        }
+
+        int allTotal = 0;
+        int allErrors = 0;
+
+        int i = 0;
+        for (PackageStats ps: packageStats.values()) {
+            data.setValue("packages." + i + ".name", ""+ps.name);
+            data.setValue("packages." + i + ".errorCount", ""+ps.errors);
+            data.setValue("packages." + i + ".totalCount", ""+ps.total);
+            data.setValue("packages." + i + ".percentGood", percent(ps.errors, ps.total));
+
+            allTotal += ps.total;
+            allErrors += ps.errors;
+
+            i++;
+        }
+
+        data.setValue("all.errorCount", ""+allErrors);
+        data.setValue("all.totalCount", ""+allTotal);
+        data.setValue("all.percentGood", percent(allErrors, allTotal));
+
+        ClearPage.write(data, "todo.cs", filename, true);
+    }
+}
+
diff --git a/build/tools/droiddoc/src/TypeInfo.java b/build/tools/droiddoc/src/TypeInfo.java
new file mode 100644 (file)
index 0000000..45e9db9
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+import java.util.*;
+import java.io.*;
+
+public class TypeInfo
+{
+    public TypeInfo(boolean isPrimitive, String dimension,
+            String simpleTypeName, String qualifiedTypeName,
+            ClassInfo cl)
+    {
+        mIsPrimitive = isPrimitive;
+        mDimension = dimension;
+        mSimpleTypeName = simpleTypeName;
+        mQualifiedTypeName = qualifiedTypeName;
+        mClass = cl;
+    }
+
+    public ClassInfo asClassInfo()
+    {
+        return mClass;
+    }
+
+    public boolean isPrimitive()
+    {
+        return mIsPrimitive;
+    }
+
+    public String dimension()
+    {
+        return mDimension;
+    }
+
+    public String simpleTypeName()
+    {
+        return mSimpleTypeName;
+    }
+
+    public String qualifiedTypeName()
+    {
+        return mQualifiedTypeName;
+    }
+
+    public String fullName()
+    {
+        if (mFullName != null) {
+            return mFullName;
+        } else {
+            return fullName(new HashSet());
+        }
+    }
+
+    public static String typeArgumentsName(TypeInfo[] args, HashSet<String> typeVars)
+    {
+        String result = "<";
+        for (int i=0; i<args.length; i++) {
+            result += args[i].fullName(typeVars);
+            if (i != args.length-1) {
+                result += ", ";
+            }
+        }
+        result += ">";
+        return result;
+    }
+
+    public String fullName(HashSet<String> typeVars)
+    {
+        mFullName = fullNameNoDimension(typeVars) + mDimension;
+        return mFullName;
+    }
+
+    public String fullNameNoDimension(HashSet<String> typeVars)
+    {
+        String fullName = null;
+        if (mIsTypeVariable) {
+            if (typeVars.contains(mQualifiedTypeName)) {
+                // don't recurse forever with the parameters.  This handles
+                // Enum<K extends Enum<K>>
+                return mQualifiedTypeName;
+            }
+            typeVars.add(mQualifiedTypeName);
+        }
+/*
+        if (fullName != null) {
+            return fullName;
+        }
+*/
+        fullName = mQualifiedTypeName;
+        if (mTypeArguments != null && mTypeArguments.length > 0) {
+            fullName += typeArgumentsName(mTypeArguments, typeVars);
+        }
+        else if (mSuperBounds != null && mSuperBounds.length > 0) {
+            fullName += " super " + mSuperBounds[0].fullName(typeVars);
+            for (int i=1; i<mSuperBounds.length; i++) {
+                fullName += " & " + mSuperBounds[i].fullName(typeVars);
+            }
+        }
+        else if (mExtendsBounds != null && mExtendsBounds.length > 0) {
+            fullName += " extends " + mExtendsBounds[0].fullName(typeVars);
+            for (int i=1; i<mExtendsBounds.length; i++) {
+                fullName += " & " + mExtendsBounds[i].fullName(typeVars);
+            }
+        }
+        return fullName;
+    }
+
+    public TypeInfo[] typeArguments()
+    {
+        return mTypeArguments;
+    }
+
+    public void makeHDF(HDF data, String base)
+    {
+        makeHDFRecursive(data, base, false, false, new HashSet<String>());
+    }
+
+    public void makeQualifiedHDF(HDF data, String base)
+    {
+        makeHDFRecursive(data, base, true, false, new HashSet<String>());
+    }
+
+    public void makeHDF(HDF data, String base, boolean isLastVararg,
+            HashSet<String> typeVariables)
+    {
+        makeHDFRecursive(data, base, false, isLastVararg, typeVariables);
+    }
+
+    public void makeQualifiedHDF(HDF data, String base, HashSet<String> typeVariables)
+    {
+        makeHDFRecursive(data, base, true, false, typeVariables);
+    }
+
+    private void makeHDFRecursive(HDF data, String base, boolean qualified,
+            boolean isLastVararg, HashSet<String> typeVars)
+    {
+        String label = qualified ? qualifiedTypeName() : simpleTypeName();
+        label += (isLastVararg) ? "..." : dimension();
+        data.setValue(base + ".label", label);
+        ClassInfo cl = asClassInfo();
+        if (mIsTypeVariable || mIsWildcard) {
+            // could link to an @param tag on the class to describe this
+            // but for now, just don't make it a link
+        }
+        else if (!isPrimitive() && cl != null && cl.isIncluded()) {
+            data.setValue(base + ".link", cl.htmlPage());
+            data.setValue(base + ".since", cl.getSince());
+        }
+
+        if (mIsTypeVariable) {
+            if (typeVars.contains(qualifiedTypeName())) {
+                // don't recurse forever with the parameters.  This handles
+                // Enum<K extends Enum<K>>
+                return;
+            }
+            typeVars.add(qualifiedTypeName());
+        }
+        if (mTypeArguments != null) {
+            TypeInfo.makeHDF(data, base + ".typeArguments", mTypeArguments, qualified, typeVars);
+        }
+        if (mSuperBounds != null) {
+            TypeInfo.makeHDF(data, base + ".superBounds", mSuperBounds, qualified, typeVars);
+        }
+        if (mExtendsBounds != null) {
+            TypeInfo.makeHDF(data, base + ".extendsBounds", mExtendsBounds, qualified, typeVars);
+        }
+    }
+
+    public static void makeHDF(HDF data, String base, TypeInfo[] types, boolean qualified,
+            HashSet<String> typeVariables)
+    {
+        final int N = types.length;
+        for (int i=0; i<N; i++) {
+            types[i].makeHDFRecursive(data, base + "." + i, qualified, false, typeVariables);
+        }
+    }
+
+    public static void makeHDF(HDF data, String base, TypeInfo[] types, boolean qualified)
+    {
+        makeHDF(data, base, types, qualified, new HashSet<String>());
+    }
+
+    void setTypeArguments(TypeInfo[] args)
+    {
+        mTypeArguments = args;
+    }
+
+    void setBounds(TypeInfo[] superBounds, TypeInfo[] extendsBounds)
+    {
+        mSuperBounds = superBounds;
+        mExtendsBounds = extendsBounds;
+    }
+
+    void setIsTypeVariable(boolean b)
+    {
+        mIsTypeVariable = b;
+    }
+
+    void setIsWildcard(boolean b)
+    {
+        mIsWildcard = b;
+    }
+
+    static HashSet<String> typeVariables(TypeInfo[] params)
+    {
+        return typeVariables(params, new HashSet());
+    }
+
+    static HashSet<String> typeVariables(TypeInfo[] params, HashSet<String> result)
+    {
+        for (TypeInfo t: params) {
+            if (t.mIsTypeVariable) {
+                result.add(t.mQualifiedTypeName);
+            }
+        }
+        return result;
+    }
+
+
+    public boolean isTypeVariable()
+    {
+        return mIsTypeVariable;
+    }
+
+    public String defaultValue() {
+        if (mIsPrimitive) {
+            if ("boolean".equals(mSimpleTypeName)) {
+                return "false";
+            } else {
+                return "0";
+            }
+        } else {
+            return "null";
+        }
+    }
+
+    @Override
+    public String toString(){
+      String returnString = "";
+      returnString += "Primitive?: " + mIsPrimitive + " TypeVariable?: " +
+      mIsTypeVariable + " Wildcard?: " + mIsWildcard + " Dimension: " + mDimension
+      + " QualifedTypeName: " + mQualifiedTypeName;
+
+      if (mTypeArguments != null){
+        returnString += "\nTypeArguments: ";
+        for (TypeInfo tA : mTypeArguments){
+          returnString += tA.qualifiedTypeName() + "(" + tA + ") ";
+        }
+      }
+      if (mSuperBounds != null){
+        returnString += "\nSuperBounds: ";
+        for (TypeInfo tA : mSuperBounds){
+          returnString += tA.qualifiedTypeName() + "(" + tA + ") ";
+        }
+      }
+      if (mExtendsBounds != null){
+        returnString += "\nExtendsBounds: ";
+        for (TypeInfo tA : mExtendsBounds){
+          returnString += tA.qualifiedTypeName() + "(" + tA + ") ";
+        }
+      }
+      return returnString;
+    }
+
+    private boolean mIsPrimitive;
+    private boolean mIsTypeVariable;
+    private boolean mIsWildcard;
+    private String mDimension;
+    private String mSimpleTypeName;
+    private String mQualifiedTypeName;
+    private ClassInfo mClass;
+    private TypeInfo[] mTypeArguments;
+    private TypeInfo[] mSuperBounds;
+    private TypeInfo[] mExtendsBounds;
+    private String mFullName;
+}
diff --git a/build/tools/droiddoc/templates-pdk/assets/android-developer-core.css b/build/tools/droiddoc/templates-pdk/assets/android-developer-core.css
new file mode 100644 (file)
index 0000000..bb4f806
--- /dev/null
@@ -0,0 +1,1297 @@
+/* file: android-developer-core.css
+   author: smain
+   date: september 2008
+   info: core developer styles (developer.android.com)
+*/
+
+
+/* RESET STYLES */
+
+html,body,div,h1,h2,h3,h4,h5,h6,p,img,
+dl,dt,dd,ol,ul,li,table,caption,tbody,
+tfoot,thead,tr,th,td,form,fieldset,
+embed,object,applet {
+  margin: 0;
+  padding: 0;
+  border: 0;
+}
+
+.rebox {
+  background:#daf3fc;
+  margin-bottom:1.5em;
+  -moz-border-radius:5px;
+  -webkit-border-radius:5px;
+}
+.rebox.lil p img {
+  display:block;
+  margin-bottom:2em;
+}
+
+.rebox .p {
+  padding:1.5em;
+  line-height:1.25em;
+}
+
+.p-r {
+  padding-right:1.5em;
+}
+
+.rebox h2, .rebox h3 {
+  font-size:16px;
+  color:#fff;
+  display:block;
+  background:url('/assets/images/rebox-gradient.gif') no-repeat center bottom #95c0d0;
+  padding:.5em .5em .5em .75em;
+  -moz-border-radius-topright:5px;
+  -moz-border-radius-topleft:5px;
+  -webkit-border-top-right-radius:5px;
+  -webkit-border-top-left-radius:5px;
+}
+
+.rebox.lil {
+}
+.rebox.lil img {
+  float:left;
+  margin:0 1em 0 0;
+  padding:0 0 3em 0;
+}
+
+.rebox.green {
+  background:#d4e9a9;
+}
+
+.rebox.green h2, .rebox.green h3 {
+  background:url('images/rebox-gradient-green.gif') no-repeat center bottom #aaca46;
+  font-weight:bold;
+}
+
+.rebox.green a:link, .rebox.green a:visited {
+  color:#360;
+}
+
+/* BASICS */
+
+html, body {
+  overflow:hidden; /* keeps scrollbar off IE */
+  background-color:#fff;
+}
+
+body {
+  font-family:arial,sans-serif;
+  color:#000;
+  font-size:13px;
+  color:#333;
+  background-image:url(images/bg_fade.jpg); 
+  background-repeat:repeat-x;
+}
+
+a, a code { 
+  color:#006699;
+} 
+
+
+a:active,
+a:active code { 
+  color:#f00;
+} 
+
+a:visited,
+a:visited code { 
+  color:#006699;
+}
+
+input, select,
+textarea, option {
+  font-family:inherit;
+  font-size:inherit;
+  padding:0;
+  margin:0;
+}
+
+option {
+  padding:0 4px;
+}
+
+p {
+  padding:0;
+  margin:0 0 1em;
+}
+
+code, pre {
+  color:#007000;
+  font-family:monospace;
+  line-height:1em;
+}
+
+var {
+  color:#007000;
+  font-style:italic;
+}
+
+pre {
+  border:1px solid #ccc;
+  background-color:#fafafa;
+  padding:10px;
+  margin:0 0 1em 1em;
+  overflow:auto;
+  line-height:inherit; /* fixes vertical scrolling in webkit */
+}
+
+h1,h2,h3,h4,h5 {
+  margin:1em 0;
+  padding:0;
+}
+
+p,ul,ol,dl,dd,dt,li {
+  line-height:1.3em;
+}
+
+ul,ol {
+  margin:0 0 .8em;
+  padding:0 0 0 2em;
+}
+
+li {
+  padding:0 0 .5em;
+}
+
+dl {
+  margin:0 0 1em 0;
+  padding:0;
+}
+
+dt {  
+  margin:0;
+  padding:0;
+}
+
+dd {
+  margin:0 0 1em;
+  padding:0 0 0 2em;
+}
+
+li p {
+  margin:.5em 0 0;
+}
+
+dd p {
+  margin:1em 0 0;
+}
+
+li pre, li table, li img {
+  margin:.5em 0 0 1em;
+}
+
+dd pre, dd table, dd img {
+  margin:1em 0 0 1em;
+}
+
+li ul,
+li ol,
+dd ul,
+dd ol {
+  margin:0;
+  padding: 0 0 0 2em;
+}
+
+li li,
+dd li {
+  margin:0;
+  padding:.5em 0 0;
+}
+
+dl dl,
+ol dl,
+ul dl {
+  margin:0 0 1em;
+  padding:0;
+}
+
+table {
+  font-size:1em;
+  margin:0 0 1em;
+  padding:0;
+  border-collapse:collapse;
+  border-width:0;
+  empty-cells:show;
+}
+
+td,th {
+  border:1px solid #ccc;
+  padding:6px 12px;
+  text-align:left;
+  vertical-align:top;
+  background-color:inherit;
+}
+
+th {
+  background-color:#dee8f1;
+}
+
+hr.blue {
+  background-color:#DDF0F2;
+  border:none;
+  height:5px;
+  margin:20px 0 10px;
+}
+
+/* LAYOUT */
+#body-content {
+  /* "Preliminary" watermark for preview releases and interim builds.
+  background:transparent url(images/preliminary.png) repeat scroll 0 0;  */
+  margin:0;
+  position:relative;
+  width:100%;
+}
+
+#header {
+  height: 114px;
+  position:relative;
+  z-index:100;
+  min-width:576px;
+  padding:0 10px;
+  border-bottom:3px solid #94b922;
+}
+
+#headerLeft{
+  padding: 25px 0 0;
+}
+
+#headerLeft img{
+  height:50px;
+  width:349px;
+}
+
+#headerRight {
+  position:absolute;
+  right:0;
+  top:0;
+  text-align:right;
+}
+
+/* Tabs in the header */
+#header ul {
+  list-style: none;
+  margin: 7px 0 0;  
+  padding: 0;
+  height: 29px;
+}
+
+#header li {
+  float: left;
+  margin: 0px 2px 0px 0px;
+  padding:0;
+}
+
+#header li a {
+  text-decoration: none;
+  display: block;
+  background-image: url(images/bg_images_sprite.png);
+  background-position: 0 -58px;
+  background-repeat: no-repeat;
+  color: #666;
+  font-size: 13px;
+  font-weight: bold;
+  width: 94px;
+  height: 29px;
+  text-align: center;
+  margin: 0px;
+}
+
+#header li a:hover {
+  background-image: url(images/bg_images_sprite.png);
+  background-position: 0 -29px;
+  background-repeat: no-repeat;
+}
+
+#header li a span {
+  position:relative;
+  top:7px;
+}
+
+#header li a span+span {
+  display:none;
+}
+
+/* TAB HIGHLIGHTING */
+.home #home-link a,
+.community #community-link a,
+.porting #porting-link a,
+.source #source-link a,
+.about #about-link a,
+.downloads #downloads-link a,
+.compatibility #compatibility-link a,
+.videos #videos-link a {
+  background-image: url(images/bg_images_sprite.png);
+  background-position: 0 0;
+  background-repeat: no-repeat;
+  color: #fff;
+  font-weight: bold;
+  cursor:default;
+}
+
+.home #home-link a:hover,
+.community #community-link a:hover,
+.home #home-link a:hover,
+.community #community-link a:hover,
+.porting #porting-link a:hover,
+.source #source-link a:hover,
+.about #about-link a:hover,
+.downloads #downloads-link a:hover,
+.compatibility #compatibility-link a:hover,
+.videos #videos-link  a:hover {
+  background-image: url(images/bg_images_sprite.png);
+  background-position: 0 0;
+}
+
+#headerLinks {
+  margin:10px 10px 0 0;
+  height:13px;
+  font-size: 11px;
+  vertical-align: top;
+}
+
+#headerLinks a {
+  color: #7FA9B5;
+}
+
+#headerLinks img {
+  vertical-align:middle;
+}
+
+#language {
+  margin:0 10px 0 4px;
+}
+
+#search {
+  height:45px;
+  margin:15px 10px 0 0;
+}
+
+/* main */
+
+#mainBodyFluid {
+  margin: 20px 10px;
+  color:#333;
+}
+
+#mainBodyFixed {
+  margin: 20px 10px;
+  color: #333;
+  width:930px;
+  position:relative;
+}
+
+#mainBodyFixed h3,
+#mainBodyFluid h3 {
+  color:#336666;
+  font-size:1.25em;
+  margin: 0em 0em 0em 0em;
+  padding-bottom:.5em;
+}
+
+#mainBodyFixed h2,
+#mainBodyFluid h2 { 
+  color:#336666;
+  font-size:1.25em;
+  margin: 0;
+  padding-bottom:.5em;
+}
+
+#mainBodyFixed h1,
+#mainBodyFluid h1 { 
+  color:#435A6E;
+  font-size:1.7em;
+  margin: 1em 0;
+}
+
+#mainBodyFixed .green,
+#mainBodyFluid .green,
+#jd-content .green { 
+  color:#7BB026;
+  background-color:none;
+}
+
+#mainBodyLeft {
+  float: left;
+  width: 600px;
+  margin-right: 20px;  
+  color: #333;
+  position:relative;
+}
+
+div.indent {
+  margin-left: 40px;  
+  margin-right: 70px;
+}
+
+#mainBodyLeft p {
+  color: #333;
+  font-size: 13px;
+}
+
+#mainBodyLeft p.blue {
+  color: #669999;
+}
+
+#mainBodyLeft #communityDiv {
+  float: left;
+  background-image:url(images/bg_community_leftDiv.jpg);
+  background-repeat: no-repeat;
+  width: 581px;
+  height: 347px;
+  padding: 20px 0px 0px 20px;
+}
+
+#mainBodyRight {
+  float: left;
+  width: 300px;
+  color: #333;
+}
+
+#mainBodyRight p {
+  padding-right: 50px;
+  color: #333;
+}
+
+#mainBodyRight table {
+  width: 100%;
+}
+
+#mainBodyRight td {
+  border:0px solid #666;
+  padding:0px 5px;
+  text-align:left;
+}
+
+#mainBodyRight .blueBorderBox {
+  border:5px solid #ddf0f2;
+  padding:18px 18px 18px 18px;
+  text-align:left;
+}
+
+#mainBodyFixed .seperator {
+  background-image:url(images/hr_gray_side.jpg);
+  background-repeat:no-repeat;
+  width: 100%;
+  float: left;
+  clear: both;
+}
+
+#mainBodyBottom {
+  float: left;
+  width: 100%;
+  clear:both;
+  color: #333;
+}
+
+#mainBodyBottom .seperator {
+  background-image:url(images/hr_gray_main.jpg);
+  background-repeat:no-repeat;
+  width: 100%;
+  float: left;
+  clear: both;
+}
+
+/* Footer */
+#footer {
+  float: left;
+  width:90%;
+  margin: 20px;
+  color: #aaa;
+  font-size: 11px;
+}
+
+#footer a {
+  color: #aaa;
+  font-size: 11px;
+}
+
+#footer a:hover {
+  text-decoration: underline;
+  color:#aaa;
+}
+
+#footerlinks {
+  margin-top:2px;
+}
+
+#footerlinks a,
+#footerlinks a:visited {
+  color:#006699;
+}
+
+#homeBottom td {
+  border:0px solid #666;
+  padding: 8px 18px 8px 18px;
+}
+
+#homeBottom table {
+  width: 100%;
+}
+
+
+#homeBottom {
+  padding: 0px 0px 0px 0px;
+  float: left;
+  width: 585px;
+  height: 165px;
+  background-image:url(images/home/bg_home_bottom.jpg);
+  background-repeat: no-repeat;
+}
+
+.groupTable {
+  width: 100%;
+}
+
+.groupTable th {
+  padding: 10px;
+  color: #ffffff;
+  background-color: #6D8293;
+  border: 2px solid #fff;
+}
+
+.groupTable td {
+  padding: 10px;
+  color: #333333;
+  background-color: #d9d9d9;
+  border: 2px solid #fff;
+}
+
+.groupTable .evenRow td {  
+  background-color: #ededed;
+}
+
+span.BigBlue {
+  color:#336666;
+  font-size:1.25em;
+  margin: 0em 0em 0em 0em;
+  padding-bottom:.5em;
+  font-weight: bold;
+}
+
+span.emBlue {
+  color: #336666;
+  font-style:italic;
+}
+
+.pageTable {
+  width: 95%;
+  border: none;
+}
+
+.pageTable img {
+vertical-align: bottom;
+}
+
+.pageTable td {
+  border: none;
+}
+
+.pageTable td.leftNav {
+  width: 100px;
+}
+
+.greenBox {
+  margin: 10px 30px 10px 30px;
+  padding: 10px 20px 10px 20px;
+  background-color: #EBF3DB;
+  width: 75%;
+}
+
+.blueBox {
+  margin: 10px 30px 10px 30px;
+  padding: 10px 20px 10px 20px;
+  background-color: #DDF0F2;
+  width: 75%;
+}
+
+.blueHR {
+  margin: 10px 30px 10px 30px;
+  height: 5px;
+  background-color: #DDF0F2;
+  width: 75%;
+}
+
+/* SEARCH FILTER */
+#search_autocomplete {
+  color:#aaa;
+}
+
+#search-button {
+  display:inline;
+}
+
+#search_filtered_div {
+  position:absolute;
+  margin-top:-1px;
+  z-index:101;
+  border:1px solid #BCCDF0;
+  background-color:#fff;
+}
+
+#search_filtered {
+  min-width:100%;
+}
+#search_filtered td{
+  background-color:#fff;
+  border-bottom: 1px solid #669999;
+  line-height:1.5em;
+}
+
+#search_filtered .jd-selected {
+  background-color: #94b922;
+  cursor:pointer;
+}
+#search_filtered .jd-selected,
+#search_filtered .jd-selected a {
+  color:#fff;
+}
+
+.no-display {
+  display: none;
+}
+
+.jd-autocomplete {
+  font-family: Arial, sans-serif;
+  padding-left: 6px;
+  padding-right: 6px;
+  padding-top: 1px;
+  padding-bottom: 1px;
+  font-size: .8em;
+  border: none;
+  margin: 0;
+  line-height: 1.05em;
+}
+
+.show-row {
+  display: table-row;
+}
+.hide-row {
+  display: hidden;
+}
+
+/* SEARCH */
+
+/* restrict global search form width */
+#searchForm {
+  width:350px;
+}
+
+#searchTxt {
+  width:200px;
+}
+
+/* disable twiddle and size selectors for left column */
+#leftSearchControl div {
+  width: 100%;
+}
+
+#leftSearchControl .gsc-twiddle {
+  background-image : none;
+}
+
+#leftSearchControl td, #searchForm td {
+  border: 0px solid #000;
+}
+
+#leftSearchControl .gsc-resultsHeader .gsc-title {
+  padding-left : 0px;
+  font-weight : bold;
+  font-size : 13px;
+  color:#006699;
+  display : none;
+}
+
+#leftSearchControl .gsc-resultsHeader div.gsc-results-selector {
+  display : none;
+}
+
+#leftSearchControl .gsc-resultsRoot {
+  padding-top : 6px;
+}
+
+#leftSearchControl div.gs-visibleUrl-long {
+  display : block;
+  color:#006699;
+}
+
+.gsc-webResult div.gs-visibleUrl-short,
+table.gsc-branding,
+.gsc-clear-button {
+  display : none;
+}
+
+.gsc-cursor-box .gsc-cursor div.gsc-cursor-page,
+.gsc-cursor-box .gsc-trailing-more-results a.gsc-trailing-more-results,
+#leftSearchControl a, 
+#leftSearchControl a b {
+  color:#006699;
+}
+
+.gsc-resultsHeader {
+  display: none;
+}
+
+/* Disable built in search forms */
+.gsc-control form.gsc-search-box {
+  display : none;
+}
+table.gsc-search-box {
+  margin:6px 0 0 0;
+  border-collapse:collapse;
+}
+
+td.gsc-input {
+  padding:0 2px;
+  width:100%;
+  vertical-align:middle;
+}
+
+input.gsc-input {
+  border:1px solid #BCCDF0;
+  width:99%;
+  padding-left:2px;
+  font-size:.95em;
+}
+
+td.gsc-search-button {
+  text-align: right;
+  padding:0;
+  vertical-align:top;
+}
+
+#search-button {
+  margin:0 0 0 2px;
+  font-size:11px;
+}
+
+/* search result tabs */
+
+#doc-content .gsc-control {
+  position:relative;
+}
+
+#doc-content .gsc-tabsArea {
+  position:relative;
+  white-space:nowrap;
+}
+
+#doc-content .gsc-tabHeader {
+  padding: 3px 6px;
+  position:relative;
+}
+
+#doc-content .gsc-tabHeader.gsc-tabhActive {
+  border-top: 2px solid #94B922;
+}
+
+#doc-content h2#searchTitle {
+  padding:0;
+}
+
+#doc-content .gsc-resultsbox-visible {
+  padding:1em 0 0 6px;
+}
+
+/* CAROUSEL */
+
+#homeMiddle {
+  padding: 0px 0px 0px 0px;
+  float: left;
+  width: 584px;
+  height: 580px;
+  position:relative;
+}
+
+#topAnnouncement {
+  background:url(images/home/bg_home_announcement.png) no-repeat 0 0;
+}
+  
+#homeTitle {
+  padding:15px 15px 0;
+  height:30px;  
+}
+
+#homeTitle h2 {
+  padding:0;
+}
+
+#announcement-block {
+  padding:0 15px 0;
+  overflow:hidden;
+  background: url(images/hr_gray_side.jpg) no-repeat 15px 0;
+  zoom:1;
+}
+
+#announcement-block>* {
+  padding:15px 0 0;
+}
+
+#announcement-block img {
+  float:left;
+  margin:0 30px 0 0;
+}
+
+#announcement {
+  float:left;
+  margin:0;
+}
+
+#carousel {
+  background:url(images/home/bg_home_carousel.png) no-repeat 0 0;
+  position:relative;
+  height:400px;
+}
+
+#carouselMain {
+       background: url(images/home/bg_home_carousel_board.png) 0 0 no-repeat;
+       height:auto;
+  padding: 25px 21px 0;
+  overflow:hidden;
+  position:relative;
+  zoom:1; /*IE6*/
+}
+
+#carouselMain img {
+  margin:0;
+}
+
+#carouselMain .bulletinDesc h3 {
+       margin:0;
+       padding:0;
+}
+
+#carouselMain .bulletinDesc p {
+       margin:0;
+       padding:0.7em 0 0;
+}
+
+#carouselWheel {
+       background: url(images/home/bg_home_carousel_wheel.png) 0 0 no-repeat;
+       padding-top:40px;
+       height:150px;
+}
+
+.clearer { clear:both; }
+
+a#arrow-left, a#arrow-right {
+  float:left;
+  width:42px;
+  height:42px;
+  background-image:url(images/home/carousel_buttons_sprite.png);
+  background-repeat:no-repeat;
+}
+a#arrow-left {
+  margin:35px 3px 0 10px;
+}
+a#arrow-right {
+  margin:35px 10px 0 0;
+}
+a.arrow-left-off,
+a#arrow-left.arrow-left-off:hover { 
+  background-position:0 0;
+}
+a.arrow-right-off, 
+a#arrow-right.arrow-right-off:hover { 
+  background-position:-42px 0;
+}
+a#arrow-left:hover { 
+  background-position:0 -42px;
+}
+a#arrow-right:hover { 
+  background-position:-42px -42px;
+}
+a.arrow-left-on {
+  background-position:0 0;
+}
+a.arrow-right-on {
+  background-position:-42px 0;
+}
+a.arrow-right-off,
+a.arrow-left-off {
+  cursor:default;
+}
+
+.app-list-container {
+  margin:0 20px;
+  position:relative;
+  width:100%;
+}
+
+div#list-clip { 
+  height:110px; 
+  width:438px;
+  overflow:hidden; 
+  position:relative; 
+  float:left; 
+}
+
+div#app-list { 
+  left:0; 
+  z-index:1; 
+  position:absolute;
+  margin:11px 0 0;
+  _margin-top:13px;
+  width:1000%;
+}
+
+#app-list a {
+  display:block;
+  float:left;
+  height:90px;
+  width:90px;
+  margin:0 24px 0;
+  padding:3px;
+  background:#99cccc;
+  -webkit-border-radius:7px;
+  -moz-border-radius:7px;
+  border-radius:7px;
+  text-decoration:none;
+  text-align:center;
+  font-size:11px;
+  line-height:11px;
+}
+
+#app-list a span {
+  position:relative;
+  top:-4px;
+}
+
+#app-list img {  
+  width:90px;
+  height:70px;
+  margin:0;
+}
+
+#app-list a.selected, 
+#app-list a:active.selected, 
+#app-list a:hover.selected {
+  background:#A4C639;
+  color:#fff;
+  cursor:default;
+  text-decoration:none;
+}
+
+#app-list a:hover, 
+#app-list a:active {
+  background:#ff9900;
+}
+
+#app-list a:hover span, 
+#app-list a:active span {
+  text-decoration:underline;
+}
+
+#droid-name {
+  padding-top:.5em;
+  color:#666;
+  padding-bottom:.25em;
+}
+
+/*IE6*/
+* html #app-list a { zoom: 1; margin:0 24px 0 15px;}
+
+* html #list-clip { 
+  width:430px !important;
+}
+
+/*carousel bulletin layouts*/
+/*460px width*/
+/*185px height*/
+.img-left {
+  float:left;
+  width:230px;
+  overflow:hidden;
+  padding:8px 0 8px 8px;
+}
+.desc-right {
+  float:left;
+  width:270px;
+  padding:10px;
+}
+.img-right {
+  float:right;
+  width:220px;
+  overflow:hidden;
+  padding:8px 8px 8px 0;
+}
+.desc-left {
+  float:right;
+  width:280px;
+  padding:10px;
+  text-align:right;
+}
+.img-top {
+  padding:20px 20px 0;
+}
+.desc-bottom {
+  padding:10px;
+}
+
+
+/* VIDEO PAGE */
+
+#mainBodyLeft.videoPlayer {
+  width:570px;
+}
+
+#mainBodyRight.videoPlayer {
+  width:330px;
+}
+
+/* player */
+
+#videoPlayerBox {
+  background-color: #DAF3FC;
+  border-radius:7px;
+  -moz-border-radius:7px;
+  -webkit-border-radius:7px;
+  width:530px;
+  padding:20px;
+  border:1px solid #d3ecf5;
+  box-shadow:2px 3px 1px #eee;
+  -moz-box-shadow:2px 3px 1px #eee;
+  -webkit-box-shadow:2px 3px 1px #eee;
+}
+
+#videoBorder {
+  background-color: #FFF;
+  min-height:399px;
+  height:auto !important;
+  border:1px solid #ccdada;
+  border-radius:7px 7px 0 0;
+  -moz-border-radius:7px 7px 0 0;
+  -webkit-border-top-left-radius:7px;
+  -webkit-border-top-right-radius:7px;
+}
+
+#videoPlayerTitle {
+  width:500px;
+  padding:15px 15px 0;
+}
+
+#videoPlayerTitle h2 {
+  font-weight:bold;
+  font-size:1.2em;
+  color:#336666;
+  margin:0;
+  padding:0;
+}
+
+#objectWrapper {
+  padding:15px 15px;
+  height:334px;
+  width:500px;
+}
+
+/* playlist tabs */
+
+ul#videoTabs {
+  list-style-type:none;
+  padding:0;
+  clear:both;
+  margin:0;
+  padding: 20px 0 0 15px;
+  zoom:1; /* IE7/8, otherwise top-padding is double */
+}
+
+ul#videoTabs li {
+  display:inline;
+  padding:0;
+  margin:0 3px 0 0;
+  line-height:2em;
+}
+
+ul#videoTabs li a {
+  border-radius:7px 7px 0 0;
+  -moz-border-radius:7px 7px 0 0;
+  -webkit-border-top-left-radius:7px;
+  -webkit-border-top-right-radius:7px;
+  background:#95c0d0;
+  color:#fff;
+  text-decoration:none;
+  padding:.45em 1.5em;
+  font-weight:bold;
+}
+
+ul#videoTabs li.selected a {
+  font-weight:bold;
+  text-decoration:none;
+  color:#555;
+  background:#daf3fc;
+  border-bottom:1px solid #daf3fc;
+}
+
+ul#videoTabs li:hover a {
+  background:#85acba;
+}
+
+ul#videoTabs li.selected:hover a {
+  background:#daf3fc;
+}
+
+/* playlists */
+
+#videos {
+  background:#daf3fc;
+  margin-bottom:1.5em;
+  padding:15px;
+  border-radius:5px;
+  -moz-border-radius:5px;
+  -webkit-border-radius:5px;
+  box-shadow:2px 3px 1px #eee;
+  -moz-box-shadow:2px 3px 1px #eee;
+  -webkit-box-shadow:2px 3px 1px #eee;
+}
+
+#videos div {
+  display:none;
+}
+
+#videos div.selected {
+  display:block;
+}
+
+ul.videoPreviews {
+  list-style:none;
+  padding:0;
+  margin:0;
+  zoom:1; /* IE, otherwise, layout doesn't update when showing 'more' */
+}
+
+ul.videoPreviews li {
+  margin:0 0 5px;
+  padding:0;
+  overflow:hidden;
+  position:relative;
+}
+
+#mainBodyFixed ul.videoPreviews h3 {
+  font-size: 12px;
+  margin:0 0 1em 130px;
+  padding:0;
+  font-weight:bold;
+  color:inherit;
+}
+
+ul.videoPreviews a {
+  margin:1px;
+  padding:10px;
+  text-decoration:none;
+  height:90px;
+  display:block;
+  border-radius:5px;
+  -moz-border-radius:5px;
+  -webkit-border-radius:5px;
+  background-color:transparent;
+}
+
+ul.videoPreviews a:hover {
+  background-color:#FFF;
+  border:none; /* IE8, otherwise, bg doesn't work */
+}
+
+ul.videoPreviews a.selected {
+  background-color: #FF9900;
+}
+
+ul.videoPreviews img {
+  float:left;
+  clear:left;
+  margin:0;
+}
+
+ul.videoPreviews h3 {
+  font-size:12px;
+  font-weight:bold;
+  text-decoration:none;
+  margin:0 0 1em 130px;
+  padding:0;
+}
+
+ul.videoPreviews p {
+  font-size: 12px;
+  text-decoration:none;
+  margin:0 0 1.2em 130px;
+}
+
+ul.videoPreviews p.full {
+  display:none;
+}
+
+ul.videoPreviews span.more {
+  padding:0 0 0 12px;
+  background:url(images/arrow_bluelink_down.png) 0 2px no-repeat;
+}
+
+ul.videoPreviews span.less {
+  padding:0 0 0 12px;
+  background:url(images/arrow_bluelink_up.png) 0 2px no-repeat;
+  display:none;
+}
+
+ul.videoPreviews p.toggle {
+  position:absolute;
+  margin:0;
+  margin-top:-23px; /* instead of bottom:23px, because IE won't do it correctly */
+  left:140px;
+}
+
+ul.videoPreviews p.toggle a {
+  height:auto;
+  margin:0;
+  padding:0;
+  zoom:1; /* IE6, otherwise the margin considers the img on redraws */
+}
+
+ul.videoPreviews p.toggle a:hover {
+  text-decoration:underline;
+  background:transparent; /* IE6, otherwise it inherits white */
+}
+
+/* featured videos */
+
+#mainBodyRight h2 {
+  padding:0 0 5px;
+}
+
+#mainBodyRight ul.videoPreviews {
+  margin:10px 0 0;
+}
+
+#mainBodyRight ul.videoPreviews li {
+  font-size:11px;
+  line-height:13px;
+  margin:0 0 5px;
+  padding:0;
+}
+
+#mainBodyRight ul.videoPreviews h3 {
+  padding:0;
+  margin:0;
+}
+
+#mainBodyRight ul.videoPreviews a {
+  text-decoration:none;
+  height:108px;
+  border:1px solid #FFF;
+}
+
+#mainBodyRight ul.videoPreviews a:hover {
+  border:1px solid #CCDADA;
+}
+
+#mainBodyRight ul.videoPreviews a.selected {
+  border:1px solid #FFF;
+}
+
+#mainBodyRight ul.videoPreviews p {
+       line-height:1.2em;
+  padding:0;
+  margin:4px 0 0 130px;
+}
+
+#mainBodyRight ul.videoPreviews img {
+       margin-top:5px;
+}
diff --git a/build/tools/droiddoc/templates-pdk/assets/android-developer-docs.js b/build/tools/droiddoc/templates-pdk/assets/android-developer-docs.js
new file mode 100644 (file)
index 0000000..59c4192
--- /dev/null
@@ -0,0 +1,464 @@
+var resizePackagesNav;
+var classesNav;
+var devdocNav;
+var sidenav;
+var content;
+var HEADER_HEIGHT = 117;
+var cookie_namespace = 'android_developer';
+var NAV_PREF_TREE = "tree";
+var NAV_PREF_PANELS = "panels";
+var nav_pref;
+var toRoot;
+var isMobile = false; // true if mobile, so we can adjust some layout
+
+function addLoadEvent(newfun) {
+  var current = window.onload;
+  if (typeof window.onload != 'function') {
+    window.onload = newfun;
+  } else {
+    window.onload = function() {
+      current();
+      newfun();
+    }
+  }
+}
+
+var agent = navigator['userAgent'];
+if ((agent.indexOf("Mobile") != -1) || 
+    (agent.indexOf("BlackBerry") != -1) || 
+    (agent.indexOf("Mini") != -1)) {
+  isMobile = true;
+  addLoadEvent(mobileSetup);
+}
+
+addLoadEvent(function() {
+window.onresize = resizeAll;
+});
+
+function mobileSetup() {
+  $("body").css({'overflow':'auto'});
+  $("html").css({'overflow':'auto'});
+  $("#body-content").css({'position':'relative', 'top':'0'});
+  $("#doc-content").css({'overflow':'visible', 'border-left':'3px solid #DDD'});
+  $("#side-nav").css({'padding':'0'});
+  $("#nav-tree").css({'overflow-y': 'auto'});
+}
+
+/* loads the lists.js file to the page.
+Loading this in the head was slowing page load time */
+addLoadEvent( function() {
+  var lists = document.createElement("script");
+  lists.setAttribute("type","text/javascript");
+  lists.setAttribute("src", toRoot+"reference/lists.js");
+  document.getElementsByTagName("head")[0].appendChild(lists);
+} );
+
+function setToRoot(root) {
+  toRoot = root;
+  // note: toRoot also used by carousel.js
+}
+
+function restoreWidth(navWidth) {
+  var windowWidth = $(window).width() + "px";
+  content.css({marginLeft:parseInt(navWidth) + 6 + "px", //account for 6px-wide handle-bar
+               width:parseInt(windowWidth) - parseInt(navWidth) - 6 + "px"});
+  sidenav.css({width:navWidth});
+  resizePackagesNav.css({width:navWidth});
+  classesNav.css({width:navWidth});
+  $("#packages-nav").css({width:navWidth});
+}
+
+function restoreHeight(packageHeight) {
+  var windowHeight = ($(window).height() - HEADER_HEIGHT);
+  var swapperHeight = windowHeight - 13;
+  $("#swapper").css({height:swapperHeight + "px"});
+  sidenav.css({height:windowHeight + "px"});
+  content.css({height:windowHeight + "px"});
+  resizePackagesNav.css({maxHeight:swapperHeight + "px", height:packageHeight});
+  classesNav.css({height:swapperHeight - parseInt(packageHeight) + "px"});
+  $("#packages-nav").css({height:parseInt(packageHeight) - 6 + "px"}); //move 6px to give space for the resize handle
+  devdocNav.css({height:sidenav.css("height")});
+  $("#nav-tree").css({height:swapperHeight + "px"});
+}
+
+function readCookie(cookie) {
+  var myCookie = cookie_namespace+"_"+cookie+"=";
+  if (document.cookie) {
+    var index = document.cookie.indexOf(myCookie);
+    if (index != -1) {
+      var valStart = index + myCookie.length;
+      var valEnd = document.cookie.indexOf(";", valStart);
+      if (valEnd == -1) {
+        valEnd = document.cookie.length;
+      }
+      var val = document.cookie.substring(valStart, valEnd);
+      return val;
+    }
+  }
+  return 0;
+}
+
+function writeCookie(cookie, val, section, expiration) {
+  if (!val) return;  
+  section = section == null ? "_" : "_"+section+"_";
+  if (expiration == null) {
+    var date = new Date();
+    date.setTime(date.getTime()+(10*365*24*60*60*1000)); // default expiration is one week
+    expiration = date.toGMTString();
+  }
+  document.cookie = cookie_namespace+section+cookie+"="+val+"; expires="+expiration+"; path=/";
+} 
+
+function init() {
+  $("#side-nav").css({position:"absolute",left:0});
+  content = $("#doc-content");
+  resizePackagesNav = $("#resize-packages-nav");
+  classesNav = $("#classes-nav");
+  sidenav = $("#side-nav");
+  devdocNav = $("#devdoc-nav");
+
+  if (location.href.indexOf("/reference/") != -1) {
+    var cookiePath = "reference_";
+  } else if (location.href.indexOf("/guide/") != -1) {
+    var cookiePath = "guide_";
+  }
+
+  if (!isMobile) {
+    $("#resize-packages-nav").resizable({handles: "s", resize: function(e, ui) { resizeHeight(); } });
+    $(".side-nav-resizable").resizable({handles: "e", resize: function(e, ui) { resizeWidth(); } });
+    var cookieWidth = readCookie(cookiePath+'width');
+    var cookieHeight = readCookie(cookiePath+'height');
+    if (cookieWidth) {
+      restoreWidth(cookieWidth);
+    } else if ($(".side-nav-resizable").length) {
+      resizeWidth();
+    }
+    if (cookieHeight) {
+      restoreHeight(cookieHeight);
+    } else {
+      resizeHeight();
+    }
+  }
+
+  if (devdocNav.length) { // only dev guide and sdk 
+    highlightNav(location.href); 
+  }
+}
+
+function highlightNav(fullPageName) {
+  fullPageName = fullPageName.replace(/^https?:\/\//, '');
+  var lastSlashPos = fullPageName.lastIndexOf("/");
+  var firstSlashPos = fullPageName.indexOf("/"); 
+  if (lastSlashPos == (fullPageName.length - 1)) { // if the url ends in slash (add 'index.html')
+    fullPageName = fullPageName + "index.html";
+  }
+  var htmlPos = fullPageName.lastIndexOf(".html", fullPageName.length);
+  var pathPageName = fullPageName.slice(firstSlashPos, htmlPos + 5);
+  var link = $("#devdoc-nav a[href$='"+ pathPageName+"']");
+  if ((link.length == 0) && (fullPageName.indexOf("/guide/") != -1)) { 
+// if there's no match, then let's backstep through the directory until we find an index.html page that matches our ancestor directories (only for dev guide)
+    lastBackstep = pathPageName.lastIndexOf("/");
+    while (link.length == 0) {
+      backstepDirectory = pathPageName.lastIndexOf("/", lastBackstep);
+      link = $("#devdoc-nav a[href$='"+ pathPageName.slice(0, backstepDirectory + 1)+"index.html']");
+      lastBackstep = pathPageName.lastIndexOf("/", lastBackstep - 1);
+      if (lastBackstep == 0) break;
+    }
+  }
+  link.parent().addClass('selected');
+  if (link.parent().parent().is(':hidden')) {
+    toggle(link.parent().parent().parent(), false);
+  } else if (link.parent().parent().hasClass('toggle-list')) {
+    toggle(link.parent().parent(), false);
+  }
+}
+
+function resizeHeight() {
+  var windowHeight = ($(window).height() - HEADER_HEIGHT);
+  var swapperHeight = windowHeight - 13;
+  $("#swapper").css({height:swapperHeight + "px"});
+  sidenav.css({height:windowHeight + "px"});
+  content.css({height:windowHeight + "px"});
+  resizePackagesNav.css({maxHeight:swapperHeight + "px"});
+  classesNav.css({height:swapperHeight - parseInt(resizePackagesNav.css("height")) + "px"});
+  $("#packages-nav").css({height:parseInt(resizePackagesNav.css("height")) - 6 + "px"}); //move 6px for handle
+  devdocNav.css({height:sidenav.css("height")});
+  $("#nav-tree").css({height:swapperHeight + "px"});
+  
+  var basePath = getBaseUri(location.pathname);
+  var section = basePath.substring(1,basePath.indexOf("/",1));
+  writeCookie("height", resizePackagesNav.css("height"), section, null);
+}
+
+function resizeWidth() {
+  var windowWidth = $(window).width() + "px";
+  if (sidenav.length) {
+    var sidenavWidth = sidenav.css("width");
+  } else {
+    var sidenavWidth = 0;
+  }
+  content.css({marginLeft:parseInt(sidenavWidth) + 6 + "px", //account for 6px-wide handle-bar
+               width:parseInt(windowWidth) - parseInt(sidenavWidth) - 6 + "px"});
+  resizePackagesNav.css({width:sidenavWidth});
+  classesNav.css({width:sidenavWidth});
+  $("#packages-nav").css({width:sidenavWidth});
+  
+  var basePath = getBaseUri(location.pathname);
+  var section = basePath.substring(1,basePath.indexOf("/",1));
+  writeCookie("width", sidenavWidth, section, null);
+}
+
+function resizeAll() {
+  if (!isMobile) {
+    resizeHeight();
+    if ($(".side-nav-resizable").length) {
+      resizeWidth();
+    }
+  }
+}
+
+function getBaseUri(uri) {
+  var intlUrl = (uri.substring(0,6) == "/intl/");
+  if (intlUrl) {
+    base = uri.substring(uri.indexOf('intl/')+5,uri.length);
+    base = base.substring(base.indexOf('/')+1, base.length);
+      //alert("intl, returning base url: /" + base);
+    return ("/" + base);
+  } else {
+      //alert("not intl, returning uri as found.");
+    return uri;
+  }
+}
+
+function requestAppendHL(uri) {
+//append "?hl=<lang> to an outgoing request (such as to blog)
+  var lang = getLangPref();
+  if (lang) {
+    var q = 'hl=' + lang;
+    uri += '?' + q;
+    window.location = uri;
+    return false;
+  } else {
+    return true;
+  }
+}
+
+function loadLast(cookiePath) {
+  var location = window.location.href;
+  if (location.indexOf("/"+cookiePath+"/") != -1) {
+    return true;
+  }
+  var lastPage = readCookie(cookiePath + "_lastpage");
+  if (lastPage) {
+    window.location = lastPage;
+    return false;
+  }
+  return true;
+}
+
+$(window).unload(function(){
+  var path = getBaseUri(location.pathname);
+  if (path.indexOf("/reference/") != -1) {
+    writeCookie("lastpage", path, "reference", null);
+  } else if (path.indexOf("/guide/") != -1) {
+    writeCookie("lastpage", path, "guide", null);
+  }
+});
+
+function toggle(obj, slide) {
+  var ul = $("ul", obj);
+  var li = ul.parent();
+  if (li.hasClass("closed")) {
+    if (slide) {
+      ul.slideDown("fast");
+    } else {
+      ul.show();
+    }
+    li.removeClass("closed");
+    li.addClass("open");
+    $(".toggle-img", li).attr("title", "hide pages");
+  } else {
+    ul.slideUp("fast");
+    li.removeClass("open");
+    li.addClass("closed");
+    $(".toggle-img", li).attr("title", "show pages");
+  }
+}
+
+function buildToggleLists() {
+  $(".toggle-list").each(
+    function(i) {
+      $("div", this).append("<a class='toggle-img' href='#' title='show pages' onClick='toggle(this.parentNode.parentNode, true); return false;'></a>");
+      $(this).addClass("closed");
+    });
+}
+
+function getNavPref() {
+  var v = readCookie('reference_nav');
+  if (v != NAV_PREF_TREE) {
+    v = NAV_PREF_PANELS;
+  }
+  return v;
+}
+
+function chooseDefaultNav() {
+  nav_pref = getNavPref();
+  if (nav_pref == NAV_PREF_TREE) {
+    $("#nav-panels").toggle();
+    $("#panel-link").toggle();
+    $("#nav-tree").toggle();
+    $("#tree-link").toggle();
+  }
+}
+
+function swapNav() {
+  if (nav_pref == NAV_PREF_TREE) {
+    nav_pref = NAV_PREF_PANELS;
+  } else {
+    nav_pref = NAV_PREF_TREE;
+    init_default_navtree(toRoot);
+  }
+  var date = new Date();
+  date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years
+  writeCookie("nav", nav_pref, "reference", date.toGMTString());
+
+  $("#nav-panels").toggle();
+  $("#panel-link").toggle();
+  $("#nav-tree").toggle();
+  $("#tree-link").toggle();
+
+  if ($("#nav-tree").is(':visible')) scrollIntoView("nav-tree");
+  else {
+    scrollIntoView("packages-nav");
+    scrollIntoView("classes-nav");
+  }
+}
+
+function scrollIntoView(nav) {
+  var navObj = $("#"+nav);
+  if (navObj.is(':visible')) {
+    var selected = $(".selected", navObj);
+    if (selected.length == 0) return;
+    if (selected.is("div")) selected = selected.parent();
+
+    var scrolling = document.getElementById(nav);
+    var navHeight = navObj.height();
+    var offsetTop = selected.position().top;
+    if (selected.parent().parent().is(".toggle-list")) offsetTop += selected.parent().parent().position().top;
+    if(offsetTop > navHeight - 92) {
+      scrolling.scrollTop = offsetTop - navHeight + 92;
+    }
+  }
+}
+
+function toggleAllInherited(linkObj, expand) {
+  var a = $(linkObj);
+  var table = $(a.parent().parent().parent());
+  var expandos = $(".jd-expando-trigger", table);
+  if ( (expand == null && a.text() == "[Expand]") || expand ) {
+    expandos.each(function(i) {
+      toggleInherited(this, true);
+    });
+    a.text("[Collapse]");
+  } else if ( (expand == null && a.text() == "[Collapse]") || (expand == false) ) {
+    expandos.each(function(i) {
+      toggleInherited(this, false);
+    });
+    a.text("[Expand]");
+  }
+  return false;
+}
+
+function toggleAllSummaryInherited(linkObj) {
+  var a = $(linkObj);
+  var content = $(a.parent().parent().parent());
+  var toggles = $(".toggle-all", content);
+  if (a.text() == "[Expand All]") {
+    toggles.each(function(i) {
+      toggleAllInherited(this, true);
+    });
+    a.text("[Collapse All]");
+  } else {
+    toggles.each(function(i) {
+      toggleAllInherited(this, false);
+    });
+    a.text("[Expand All]");
+  }
+  return false;
+}
+
+
+function changeTabLang(lang) {
+  var nodes = $("#header-tabs").find("."+lang);
+  for (i=0; i < nodes.length; i++) { // for each node in this language 
+    var node = $(nodes[i]);
+    node.siblings().css("display","none"); // hide all siblings 
+    if (node.not(":empty").length != 0) { //if this languages node has a translation, show it 
+      node.css("display","inline");
+    } else { //otherwise, show English instead 
+      node.css("display","none");
+      node.siblings().filter(".en").css("display","inline");
+    }
+  }
+}
+
+function changeNavLang(lang) {
+  var nodes = $("#side-nav").find("."+lang);
+  for (i=0; i < nodes.length; i++) { // for each node in this language 
+    var node = $(nodes[i]);
+    node.siblings().css("display","none"); // hide all siblings 
+    if (node.not(":empty").length != 0) { // if this languages node has a translation, show it 
+      node.css("display","inline");
+    } else { // otherwise, show English instead 
+      node.css("display","none");
+      node.siblings().filter(".en").css("display","inline");
+    }
+  }
+}
+
+function changeDocLang(lang) {
+  changeTabLang(lang);
+  changeNavLang(lang);
+}
+
+function changeLangPref(lang, refresh) {
+  var date = new Date();
+  expires = date.toGMTString(date.setTime(date.getTime()+(10*365*24*60*60*1000))); // keep this for 50 years
+  //alert("expires: " + expires)
+  writeCookie("pref_lang", lang, null, expires);
+  //changeDocLang(lang);
+  if (refresh) {
+    l = getBaseUri(location.pathname);
+    window.location = l;
+  }
+}
+
+function loadLangPref() {
+  var lang = readCookie("pref_lang");
+  if (lang != 0) {
+    $("#language").find("option[value='"+lang+"']").attr("selected",true);
+  }
+}
+
+function getLangPref() {
+  var lang = $("#language").find(":selected").attr("value");
+  if (!lang) {
+    lang = readCookie("pref_lang");
+  }
+  return (lang != 0) ? lang : 'en';
+}
+
+
+function toggleContent(obj) {
+  var button = $(obj);
+  var div = $(obj.parentNode);
+  var toggleMe = $(".toggle-content-toggleme",div);
+  if (button.hasClass("show")) {
+    toggleMe.slideDown();
+    button.removeClass("show").addClass("hide");
+  } else {
+    toggleMe.slideUp();
+    button.removeClass("hide").addClass("show");
+  }
+  $("span", button).toggle();
+}
diff --git a/build/tools/droiddoc/templates-pdk/assets/favicon.ico b/build/tools/droiddoc/templates-pdk/assets/favicon.ico
new file mode 100644 (file)
index 0000000..d8884b7
Binary files /dev/null and b/build/tools/droiddoc/templates-pdk/assets/favicon.ico differ
diff --git a/build/tools/droiddoc/templates-pdk/assets/images/rebox-gradient.gif b/build/tools/droiddoc/templates-pdk/assets/images/rebox-gradient.gif
new file mode 100644 (file)
index 0000000..124e844
Binary files /dev/null and b/build/tools/droiddoc/templates-pdk/assets/images/rebox-gradient.gif differ
diff --git a/build/tools/droiddoc/templates-pdk/assets/placeholder b/build/tools/droiddoc/templates-pdk/assets/placeholder
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/build/tools/droiddoc/templates-pdk/customization.cs b/build/tools/droiddoc/templates-pdk/customization.cs
new file mode 100644 (file)
index 0000000..3e9be06
--- /dev/null
@@ -0,0 +1,182 @@
+<?cs # This file defines custom definitions for the masthead (logo, searchbox, tabs, etc) and 
+left nav (toc) that gets placed on all pages, for the open source site?>
+
+<?cs 
+def:custom_masthead() ?>
+  <div id="header">
+      <div id="headerLeft">
+          <a href="<?cs var:toroot?>" tabindex="-1"><img
+              src="<?cs var:toroot ?>assets/images/open_source.png" alt="Android Open Source Project" /></a>
+          <ul class="<?cs if:home ?>home<?cs
+                      elif:doc.type == "source" ?>source<?cs
+                      elif:doc.type == "porting" ?>porting<?cs
+                      elif:doc.type == "compatibility" ?>compatibility<?cs
+                      elif:doc.type == "downloads" ?>downloads<?cs
+                      elif:doc.type == "community" ?>community<?cs
+                      elif:doc.type == "about" ?>about<?cs /if ?>">
+              <li id="home-link"><a href="<?cs var:toroot ?>index.html"><span>Home</span></a></li>
+              <li id="source-link"><a href="<?cs var:toroot ?>source/index.html"
+                                  onClick="return loadLast('source')"><span>Source</span></a></li>
+              <li id="porting-link"><a href="<?cs var:toroot ?>porting/index.html"
+                                  onClick="return loadLast('porting')"><span>Porting</span></a></li>
+              <li id="compatibility-link"><a href="<?cs var:toroot ?>compatibility/index.html"
+                                  onClick="return loadLast('compatibility')"><span>Compatibility</span></a></li>
+              <li id="community-link"><a href="<?cs var:toroot ?>community/index.html"
+                                  onClick="return loadLast('community')"><span>Community</span></a></li>
+              <li id="downloads-link"><a href="<?cs var:toroot ?>downloads/index.html"
+                                  onClick="return loadLast('downloads')"><span>Downloads</span></a></li>
+              <li id="about-link"><a href="<?cs var:toroot ?>about/index.html"
+                                  onClick="return loadLast('about')"><span>About</span></a></li>
+          </ul> 
+      </div>
+      <div id="headerRight">
+          <div id="headerLinks">
+            <!-- <img src="<?cs var:toroot ?>assets/images/icon_world.jpg" alt="" /> -->
+            <span class="text">
+              <!-- &nbsp;<a href="#">English</a> | -->
+              <a href="http://www.android.com">Android.com</a>
+            </span>
+          </div>
+      </div><!-- headerRight -->
+  </div><!-- header --><?cs 
+/def ?><?cs # custom_masthead ?>
+
+
+<?cs def:community_nav() ?>
+  <div class="g-section g-tpl-240" id="body-content">
+    <div class="g-unit g-first side-nav-resizable" id="side-nav">
+      <div id="devdoc-nav"><?cs 
+        include:"../../../../development/pdk/docs/community/community_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      addLoadEvent(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+  </div>
+<?cs /def ?>
+
+<?cs def:about_nav() ?>
+  <div class="g-section g-tpl-240" id="body-content">
+    <div class="g-unit g-first side-nav-resizable" id="side-nav">
+      <div id="devdoc-nav"><?cs
+        include:"../../../../development/pdk/docs/about/about_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      addLoadEvent(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+  </div>
+<?cs /def ?>
+
+<?cs def:porting_nav() ?>
+  <div class="g-section g-tpl-240" id="body-content">
+    <div class="g-unit g-first side-nav-resizable" id="side-nav">
+      <div id="devdoc-nav"><?cs
+        include:"../../../../development/pdk/docs/porting/porting_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      addLoadEvent(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+  </div>
+<?cs /def ?>
+
+<?cs def:source_nav() ?>
+  <div class="g-section g-tpl-240" id="body-content">
+    <div class="g-unit g-first side-nav-resizable" id="side-nav">
+      <div id="devdoc-nav"><?cs
+        include:"../../../../development/pdk/docs/source/source_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      addLoadEvent(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+  </div>
+<?cs /def ?>
+
+<?cs def:downloads_nav() ?>
+  <div class="g-section g-tpl-240" id="body-content">
+    <div class="g-unit g-first side-nav-resizable" id="side-nav">
+      <div id="devdoc-nav"><?cs
+        include:"../../../../development/pdk/docs/downloads/downloads_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      addLoadEvent(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+  </div>
+<?cs /def ?>
+
+<?cs def:compatibility_nav() ?>
+  <div class="g-section g-tpl-240" id="body-content">
+    <div class="g-unit g-first side-nav-resizable" id="side-nav">
+      <div id="devdoc-nav"><?cs
+        include:"../../../../development/pdk/docs/compatibility/compatibility_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      addLoadEvent(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+  </div>
+<?cs /def ?>
+
+<?cs def:custom_left_nav() ?>
+  <?cs if:doc.hidenav != "true" ?>
+    <?cs if:doc.type == "source" ?>
+      <?cs call:source_nav() ?>
+    <?cs elif:doc.type == "porting" ?>
+      <?cs call:porting_nav() ?>
+    <?cs elif:doc.type == "compatibility" ?>
+      <?cs call:compatibility_nav() ?>
+    <?cs elif:doc.type == "downloads" ?>
+      <?cs call:downloads_nav() ?>
+    <?cs elif:doc.type == "community" ?>
+      <?cs call:community_nav() ?>
+    <?cs elif:doc.type == "about" ?>
+      <?cs call:about_nav() ?>
+    <?cs /if ?>
+  <?cs /if ?>
+<?cs /def ?>
+
+<?cs # appears at the bottom of every page ?><?cs 
+def:custom_cc_copyright() ?>
+  Except as noted, this content is 
+  licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
+  Creative Commons Attribution 2.5</a>. For details and 
+  restrictions, see the <a href="http://developer.android.com/license.html">Content 
+  License</a>.<?cs 
+/def ?>
+
+<?cs 
+def:custom_copyright() ?>
+  Except as noted, this content is licensed under <a
+  href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0</a>. 
+  For details and restrictions, see the <a href="http://developer.android.com/license.html">
+  Content License</a>.<?cs 
+/def ?>
+
+<?cs 
+def:custom_footerlinks() ?>
+  <p>
+    <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+    <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+    <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+  </p><?cs 
+/def ?>
+
+<?cs # appears on the right side of the blue bar at the bottom off every page ?><?cs 
+def:custom_buildinfo() ?>
+  Android <?cs var:sdk.platform.version ?>&nbsp;r<?cs var:sdk.rel.id ?> - <?cs var:page.now ?>
+<?cs /def ?>
diff --git a/build/tools/droiddoc/templates-pdk/data.hdf b/build/tools/droiddoc/templates-pdk/data.hdf
new file mode 100644 (file)
index 0000000..9411b78
--- /dev/null
@@ -0,0 +1,4 @@
+template {
+    which = normal
+}
+
diff --git a/build/tools/droiddoc/templates-pdk/head_tag.cs b/build/tools/droiddoc/templates-pdk/head_tag.cs
new file mode 100644 (file)
index 0000000..915dc0e
--- /dev/null
@@ -0,0 +1,46 @@
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link rel="shortcut icon" type="image/x-icon" href="<?cs var:toroot ?>assets-pdk/favicon.ico" />
+<title><?cs 
+  if:page.title ?><?cs 
+    var:page.title ?><?cs
+    if:sdk.version ?> (<?cs
+      var:sdk.version ?>)<?cs
+    /if ?> | <?cs
+  /if ?>Android Open Source</title>
+<link href="<?cs var:toroot ?>assets/android-developer-docs-devguide.css" rel="stylesheet" type="text/css" />
+<link href="<?cs var:toroot ?>assets-pdk/pdk-local.css" rel="stylesheet" type="text/css" />
+<script src="<?cs var:toroot ?>assets/search_autocomplete.js" type="text/javascript"></script>
+<script src="<?cs var:toroot ?>assets/jquery-resizable.min.js" type="text/javascript"></script>
+<script src="<?cs var:toroot ?>assets/android-developer-docs.js" type="text/javascript"></script>
+<script type="text/javascript">
+  setToRoot("<?cs var:toroot ?>");
+</script>
+<script type="text/javascript">
+  function resizeDoxFrameHeight() {
+       if(document.getElementById && !(document.all)) {
+               height= document.getElementById('doxygen').contentDocument.body.scrollHeight + 20;
+               document.getElementById('doxygen').style.height = height+"pt";
+       }
+       else if(document.all) {
+               height= document.frames('doxygen').document.body.scrollHeight + 20;
+               document.all.doxygen.style.height = height;
+       }
+}
+</script>
+<script type="text/javascript>
+  jQuery(document).ready(function() {
+        jQuery("pre").addClass("prettyprint");
+  });
+</script>
+<noscript>
+  <style type="text/css">
+    body{overflow:auto;}
+    #body-content{position:relative; top:0;}
+    #doc-content{overflow:visible;border-left:3px solid #666;}
+    #side-nav{padding:0;}
+    #side-nav .toggle-list ul {display:block;}
+    #resize-packages-nav{border-bottom:3px solid #666;}
+  </style>
+</noscript>
+</head>
diff --git a/build/tools/droiddoc/templates-sdk/assets-sdk/placeholder b/build/tools/droiddoc/templates-sdk/assets-sdk/placeholder
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/build/tools/droiddoc/templates-sdk/customization.cs b/build/tools/droiddoc/templates-sdk/customization.cs
new file mode 100644 (file)
index 0000000..907f0f7
--- /dev/null
@@ -0,0 +1,252 @@
+<?cs # This default template file is meant to be replaced. ?>
+<?cs # Use the -tempatedir arg to javadoc to set your own directory with a replacement for this file in it. ?>
+
+
+<?cs # The default search box that goes in the header ?><?cs 
+def:default_search_box() ?>
+  <div id="search" >
+      <div id="searchForm">
+          <form accept-charset="utf-8" class="gsc-search-box" 
+                onsubmit="return submit_search()">
+            <table class="gsc-search-box" cellpadding="0" cellspacing="0"><tbody>
+                <tr>
+                  <td class="gsc-input">
+                    <input id="search_autocomplete" class="gsc-input" type="text" size="33" autocomplete="off"
+                      title="search developer docs" name="q"
+                      value="search developer docs"
+                      onFocus="search_focus_changed(this, true)"
+                      onBlur="search_focus_changed(this, false)"
+                      onkeydown="return search_changed(event, true, '<?cs var:toroot?>')"
+                      onkeyup="return search_changed(event, false, '<?cs var:toroot?>')" />
+                  <div id="search_filtered_div" class="no-display">
+                      <table id="search_filtered" cellspacing=0>
+                      </table>
+                  </div>
+                  </td>
+                  <td class="gsc-search-button">
+                    <input type="submit" value="Search" title="search" id="search-button" class="gsc-search-button" />
+                  </td>
+                  <td class="gsc-clear-button">
+                    <div title="clear results" class="gsc-clear-button">&nbsp;</div>
+                  </td>
+                </tr></tbody>
+              </table>
+          </form>
+      </div><!-- searchForm -->
+  </div><!-- search --><?cs 
+/def ?>
+
+<?cs 
+def:custom_masthead() ?>
+  <div id="header">
+      <div id="headerLeft">
+          <a href="<?cs var:toroot ?>index.html" tabindex="-1"><img
+              src="<?cs var:toroot ?>assets/images/bg_logo.png" alt="Android Developers" /></a>
+          <?cs include:"header_tabs.cs" ?>     <?cs # The links are extracted so we can better manage localization ?>
+      </div>
+      <div id="headerRight">
+          <div id="headerLinks">
+          <?cs if:template.showLanguageMenu ?>
+            <img src="<?cs var:toroot ?>assets/images/icon_world.jpg" alt="Language:" /> 
+            <span id="language">
+               <select name="language" onChange="changeLangPref(this.value, true)">
+                               <option value="en">English&nbsp;&nbsp;&nbsp;</option>
+                               <option value="ja">日本語</option>
+                               <?cs # 
+                           <option value="de">Deutsch</option> 
+                               <option value="es">Español</option>
+                               <option value="fr">Français</option>
+                               <option value="it">Italiano</option>
+                               <option value="zh-CN">中文 (简体)</option>
+                               <option value="zh-TW">中文 (繁體)</option>
+                           ?>
+               </select>       
+               <script type="text/javascript">
+                 <!--  
+                  loadLangPref();  
+                  //-->
+               </script>
+            </span>
+          <?cs /if ?>
+          <a href="http://www.android.com">Android.com</a>
+          </div><?cs 
+          call:default_search_box() ?><?cs 
+                 if:reference ?>
+                         <div id="api-level-toggle">
+                           <input type="checkbox" id="apiLevelCheckbox" onclick="toggleApiLevelSelector(this)" />
+                           <label for="apiLevelCheckbox" class="disabled">Filter by API Level: </label>
+                           <select id="apiLevelSelector">
+                             <!-- option elements added by buildApiLevelSelector() -->
+                           </select>
+                         </div>
+                   <script>
+              var SINCE_DATA = [ <?cs 
+                each:since = since ?>'<?cs 
+                  var:since.name ?>'<?cs 
+                  if:!last(since) ?>, <?cs /if ?><?cs
+                /each 
+              ?> ];
+              buildApiLevelSelector();
+            </script><?cs 
+                       /if ?>
+      </div><!-- headerRight -->
+      <script type="text/javascript">
+        <!--  
+        changeTabLang(getLangPref());
+        //-->
+      </script>
+  </div><!-- header --><?cs 
+/def ?>
+
+<?cs 
+def:sdk_nav() ?>
+  <div class="g-section g-tpl-240" id="body-content">
+    <div class="g-unit g-first" id="side-nav">
+      <div id="devdoc-nav"><?cs 
+        include:"../../../../frameworks/base/docs/html/sdk/sdk_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+<?cs /def ?>
+
+<?cs 
+def:resources_tab_nav() ?>
+  <div class="g-section g-tpl-200" id="body-content">
+    <div class="g-unit g-first" id="side-nav">
+      <div id="devdoc-nav"><?cs 
+        include:"../../../../frameworks/base/docs/html/resources/resources_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      addLoadEvent(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?>
+
+<?cs 
+def:guide_nav() ?>
+  <div class="g-section g-tpl-240" id="body-content">
+    <div class="g-unit g-first" id="side-nav">
+      <div id="devdoc-nav"><?cs 
+        include:"../../../../frameworks/base/docs/html/guide/guide_toc.cs" ?>
+      </div>
+    </div> <!-- end side-nav -->
+    <script>
+      addLoadEvent(function() {
+        scrollIntoView("devdoc-nav");
+        });
+    </script>
+<?cs /def ?>
+
+<?cs # The default side navigation for the reference docs ?><?cs 
+def:default_left_nav() ?>
+  <div class="g-section g-tpl-240" id="body-content">
+    <div class="g-unit g-first" id="side-nav">
+      <div id="swapper">
+        <div id="nav-panels">
+          <div id="resize-packages-nav">
+            <div id="packages-nav">
+              <div id="index-links"><nobr>
+                <a href="<?cs var:toroot ?>reference/packages.html" <?cs if:(page.title == "Package Index") ?>class="selected"<?cs /if ?> >Package Index</a> | 
+                <a href="<?cs var:toroot ?>reference/classes.html" <?cs if:(page.title == "Class Index") ?>class="selected"<?cs /if ?>>Class Index</a></nobr>
+              </div>
+              <ul>
+               <?cs call:package_link_list(docs.packages) ?>
+              </ul><br/>
+            </div> <!-- end packages -->
+          </div> <!-- end resize-packages -->
+          <div id="classes-nav"><?cs 
+            if:subcount(class.package) ?>
+            <ul>
+              <?cs call:list("Interfaces", class.package.interfaces) ?>
+              <?cs call:list("Classes", class.package.classes) ?>
+              <?cs call:list("Enums", class.package.enums) ?>
+              <?cs call:list("Exceptions", class.package.exceptions) ?>
+              <?cs call:list("Errors", class.package.errors) ?>
+            </ul><?cs 
+            elif:subcount(package) ?>
+            <ul>
+              <?cs call:class_link_list("Interfaces", package.interfaces) ?>
+              <?cs call:class_link_list("Classes", package.classes) ?>
+              <?cs call:class_link_list("Enums", package.enums) ?>
+              <?cs call:class_link_list("Exceptions", package.exceptions) ?>
+              <?cs call:class_link_list("Errors", package.errors) ?>
+            </ul><?cs 
+            else ?>
+              <script>
+                /*addLoadEvent(maxPackageHeight);*/
+              </script>
+              <p style="padding:10px">Select a package to view its members</p><?cs 
+            /if ?><br/>
+          </div><!-- end classes -->
+        </div><!-- end nav-panels -->
+        <div id="nav-tree" style="display:none">
+          <div id="index-links"><nobr>
+            <a href="<?cs var:toroot ?>reference/packages.html" <?cs if:(page.title == "Package Index") ?>class="selected"<?cs /if ?> >Package Index</a> | 
+            <a href="<?cs var:toroot ?>reference/classes.html" <?cs if:(page.title == "Class Index") ?>class="selected"<?cs /if ?>>Class Index</a></nobr>
+          </div>
+        </div><!-- end nav-tree -->
+      </div><!-- end swapper -->
+    </div> <!-- end side-nav -->
+    <script>
+      if (!isMobile) {
+        $("<a href='#' id='nav-swap' onclick='swapNav();return false;' style='font-size:10px;line-height:9px;margin-left:1em;text-decoration:none;'><span id='tree-link'>Use Tree Navigation</span><span id='panel-link' style='display:none'>Use Panel Navigation</span></a>").appendTo("#side-nav");
+        chooseDefaultNav();
+        if ($("#nav-tree").is(':visible')) {
+          init_default_navtree("<?cs var:toroot ?>");
+        } else {
+          addLoadEvent(function() {
+            scrollIntoView("packages-nav");
+            scrollIntoView("classes-nav");
+          });
+        }
+        $("#swapper").css({borderBottom:"2px solid #aaa"});
+      } else {
+        swapNav(); // tree view should be used on mobile
+      }
+    </script><?cs 
+/def ?>
+
+<?cs 
+def:custom_left_nav() ?><?cs 
+  if:guide ?><?cs 
+    call:guide_nav() ?><?cs 
+  elif:resources ?><?cs 
+    call:resources_tab_nav() ?><?cs 
+  elif:sdk ?><?cs 
+    call:sdk_nav() ?><?cs 
+  else ?><?cs 
+    call:default_left_nav() ?><?cs 
+  /if ?><?cs 
+/def ?>
+
+<?cs # appears at the bottom of every page ?><?cs 
+def:custom_cc_copyright() ?>
+  Except as noted, this content is 
+  licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
+  Creative Commons Attribution 2.5</a>. For details and 
+  restrictions, see the <a href="<?cs var:toroot ?>license.html">Content 
+  License</a>.<?cs 
+/def ?>
+
+<?cs 
+def:custom_copyright() ?>
+  Except as noted, this content is licensed under <a
+  href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0</a>. 
+  For details and restrictions, see the <a href="<?cs var:toroot ?>license.html">
+  Content License</a>.<?cs 
+/def ?>
+
+<?cs 
+def:custom_footerlinks() ?>
+  <p>
+    <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+    <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+    <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+  </p><?cs 
+/def ?>
+
+<?cs # appears on the right side of the blue bar at the bottom off every page ?><?cs 
+def:custom_buildinfo() ?>
+  Android <?cs var:sdk.version ?>&nbsp;r<?cs var:sdk.rel.id ?> - <?cs var:page.now ?>
+<?cs /def ?>
diff --git a/build/tools/droiddoc/templates-sdk/data.hdf b/build/tools/droiddoc/templates-sdk/data.hdf
new file mode 100644 (file)
index 0000000..9411b78
--- /dev/null
@@ -0,0 +1,4 @@
+template {
+    which = normal
+}
+
diff --git a/build/tools/droiddoc/templates-sdk/header_tabs.cs b/build/tools/droiddoc/templates-sdk/header_tabs.cs
new file mode 100644 (file)
index 0000000..496f276
--- /dev/null
@@ -0,0 +1,89 @@
+<ul id="header-tabs" class="<?cs 
+       if:reference ?>reference<?cs
+       elif:guide ?>guide<?cs
+       elif:sdk ?>sdk<?cs
+       elif:home ?>home<?cs
+       elif:resources ?>resources<?cs
+       elif:videos ?>videos<?cs /if ?>">
+    
+       <li id="home-link"><a href="<?cs var:toroot ?><?cs 
+                                   if:android.whichdoc != "online" ?>offline.html<?cs 
+                                   else ?>index.html<?cs /if ?>">
+       <?cs if:!sdk.redirect ?>
+               <span class="en">Home</span>
+               <span style="display:none" class="de">Startseite</span>
+               <span style="display:none" class="es"></span>
+               <span style="display:none" class="fr"></span>
+               <span style="display:none" class="it"></span>
+               <span style="display:none" class="ja">ホーム</span>
+               <span style="display:none" class="zh-CN">主页</span>
+               <span style="display:none" class="zh-TW">首頁</span>
+       <?cs /if ?>
+       </a></li>
+       <li id="sdk-link"><a href="<?cs var:toroot ?>sdk/index.html">
+               <span class="en">SDK</span>
+       </a></li>
+       <li id="guide-link"><a href="<?cs var:toroot ?>guide/index.html" onClick="return loadLast('guide')">
+       <?cs if:!sdk.redirect ?>
+               <span class="en">Dev Guide</span>
+               <span style="display:none" class="de">Handbuch</span>
+               <span style="display:none" class="es">Guía</span>
+               <span style="display:none" class="fr">Guide</span>
+               <span style="display:none" class="it">Guida</span>
+               <span style="display:none" class="ja">開発ガイド</span>
+               <span style="display:none" class="zh-CN">开发人员指南</span>
+               <span style="display:none" class="zh-TW">開發指南</span>
+       <?cs /if ?>
+       </a></li>
+       <li id="reference-link"><a href="<?cs var:toroot ?>reference/packages.html" onClick="return loadLast('reference')">
+       <?cs if:!sdk.redirect ?>
+               <span class="en">Reference</span>
+               <span style="display:none" class="de">Referenz</span>
+               <span style="display:none" class="es">Referencia</span>
+               <span style="display:none" class="fr">Référence</span>
+               <span style="display:none" class="it">Riferimento</span>
+               <span style="display:none" class="ja">リファレンス</span>
+               <span style="display:none" class="zh-CN">参考</span>
+               <span style="display:none" class="zh-TW">參考資料</span>
+       <?cs /if ?>
+       </a></li>
+       <li id="resources-link"><a href="<?cs var:toroot ?>resources/index.html" onClick="return loadLast('resources')">
+       <?cs if:!sdk.redirect ?>
+               <span class="en">Resources</span>
+               <span style="display:none" class="de"></span>
+               <span style="display:none" class="es"></span>
+               <span style="display:none" class="fr"></span>
+               <span style="display:none" class="it"></span>
+               <span style="display:none" class="ja"></span>
+               <span style="display:none" class="zh-CN"></span>
+               <span style="display:none" class="zh-TW"></span>
+       <?cs /if ?>
+       </a></li>
+       <li id="videos-link"><a href="<?cs var:toroot ?>videos/index.html" onClick="return loadLast('videos')">
+       <?cs if:!sdk.redirect ?>
+               <span class="en">Videos</span>
+               <span style="display:none" class="de"></span>
+               <span style="display:none" class="es"></span>
+               <span style="display:none" class="fr"></span>
+               <span style="display:none" class="it"></span>
+               <span style="display:none" class="ja">ビデオ</span>
+               <span style="display:none" class="zh-CN"></span>
+               <span style="display:none" class="zh-TW"></span>
+       <?cs /if ?>
+       </a></li>
+       <li><a href="http://android-developers.blogspot.com" onClick="return requestAppendHL(this.href)">
+       <?cs if:!sdk.redirect ?>
+               <span class="en">Blog</span>
+               <span style="display:none" class="de"></span>
+               <span style="display:none" class="es"></span>
+               <span style="display:none" class="fr"></span>
+               <span style="display:none" class="it"></span>
+               <span style="display:none" class="ja">ブログ</span>
+               <span style="display:none" class="zh-CN">博客</span>
+               <span style="display:none" class="zh-TW">網誌</span>
+       <?cs /if ?>
+       </a></li>
+
+
+     
+</ul>
diff --git a/build/tools/droiddoc/templates-sdk/sdkpage.cs b/build/tools/droiddoc/templates-sdk/sdkpage.cs
new file mode 100644 (file)
index 0000000..77bb959
--- /dev/null
@@ -0,0 +1,277 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<html>
+<?cs if:sdk.redirect ?>
+  <head>
+    <title>Redirecting...</title>
+    <meta http-equiv="refresh" content="0;url=<?cs var:toroot ?>sdk/<?cs
+      if:sdk.redirect.path ?><?cs var:sdk.redirect.path ?><?cs
+      else ?>index.html<?cs /if ?>">
+    <link href="<?cs var:toroot ?>assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+  </head>
+<?cs else ?>
+  <?cs include:"head_tag.cs" ?>
+<?cs /if ?>
+<body class="gc-documentation">
+<a name="top"></a>
+<?cs call:custom_masthead() ?>
+
+<?cs call:sdk_nav() ?>
+
+<?cs if:sdk.redirect ?>
+
+<div class="g-unit">
+  <div id="jd-content">
+    <p>Redirecting to
+    <a href="<?cs var:toroot ?>sdk/<?cs
+      if:sdk.redirect.path ?><?cs var:sdk.redirect.path ?><?cs
+      else ?>index.html<?cs /if ?>"><?cs
+      if:sdk.redirect.path ?><?cs var:sdk.redirect.path ?><?cs
+      else ?>Download the SDK<?cs /if ?>
+    </a> ...</p>
+<?cs else ?>
+<div class="g-unit" id="doc-content" >
+  <div id="jd-header" class="guide-header" >
+    <span class="crumb">&nbsp;</span>
+    <h1><?cs if:android.whichdoc == "online" ?>Download the <?cs /if ?><?cs var:page.title ?></h1>
+  </div>
+
+  <div id="jd-content">
+    <?cs
+    if:ndk ?><?cs
+    else ?><?cs
+      if:android.whichdoc == "online" ?><p><em><?cs
+      var:sdk.date ?></em></p><?cs
+      /if ?><?cs
+    /if ?>
+
+<?cs if:sdk.not_latest_version ?>
+  <div class="special">
+    <p><strong>This is NOT the current Android SDK release.</strong></p>
+    <p><a href="/sdk/index.html">Download the current Android SDK</a></p>
+  </div>
+<?cs /if ?>
+
+<?cs if:android.whichdoc != "online" && !android.preview ?>
+
+<!-- <p>The sections below provide an overview of how to install the SDK package. </p> -->
+
+<?cs else ?>
+  <?cs if:ndk ?>
+
+<p>The Android NDK is a companion tool to the Android SDK that lets you build
+performance-critical portions of your apps in native code. It provides headers and
+libraries that allow you to build activities, handle user input, use hardware sensors,
+access application resources, and more, when programming in C or C++. If you write
+native code, your applications are still packaged into an .apk file and they still run
+inside of a virtual machine on the device. The fundamental Android application model
+does not change.</p>
+
+<p>Using native code does not result in an automatic performance increase, 
+but always increases application complexity. If you have not run into any limitations
+using the Android framework APIs, you probably do not need the NDK. Read <a 
+href="<?cs var:toroot ?>sdk/ndk/overview.html">What is the NDK?</a> for more information about what
+the NDK offers and whether it will be useful to you.
+</p>
+<p>
+The NDK is designed for use <em>only</em> in conjunction with the
+Android SDK. If you have not already installed and setup the <a
+href="http://developer.android.com/sdk/index.html">Android SDK</a>, please
+do so before downloading the NDK. 
+</p>
+
+  <table class="download">
+    <tr>
+      <th>Platform</th>
+      <th>Package</th>
+      <th>Size</th>
+      <th>MD5 Checksum</th>
+  </tr>
+  <tr>
+    <td>Windows</td>
+    <td>
+  <a href="http://dl.google.com/android/ndk/<?cs var:ndk.win_download ?>"><?cs var:ndk.win_download ?></a>
+    </td>
+    <td><?cs var:ndk.win_bytes ?> bytes</td>
+    <td><?cs var:ndk.win_checksum ?></td>
+  </tr>
+  <tr class="alt-color">
+    <td>Mac OS X (intel)</td>
+    <td>
+  <a href="http://dl.google.com/android/ndk/<?cs var:ndk.mac_download ?>"><?cs var:ndk.mac_download ?></a>
+    </td>
+    <td><?cs var:ndk.mac_bytes ?> bytes</td>
+    <td><?cs var:ndk.mac_checksum ?></td>
+  </tr>
+  <tr>
+    <td>Linux 32/64-bit (x86)</td>
+    <td>
+  <a href="http://dl.google.com/android/ndk/<?cs var:ndk.linux_download ?>"><?cs var:ndk.linux_download ?></a>
+    </td>
+    <td><?cs var:ndk.linux_bytes ?> bytes</td>
+    <td><?cs var:ndk.linux_checksum ?></td>
+  </tr>
+  </table>
+
+  <?cs else ?><?cs if:android.whichdoc == "online" ?>
+
+  <?cs if:sdk.preview ?>
+  <p>Welcome developers! The next release of the Android platform will be
+  Android 1.6 and we are pleased to announce the availability of an early look
+  SDK to give you a head-start on developing applications for it. </p>
+
+  <p>The Android <?cs var:sdk.preview.version ?> platform includes a variety of
+  improvements and new features for users and developers. Additionally, the SDK
+  itself introduces several new capabilities that enable you to develop
+  applications more efficiently. See the <a href="features.html">Android <?cs
+  var:sdk.preview.version ?> Platform Highlights</a> document for a list of
+  highlights.</p>
+<?cs /if ?>
+<?cs # end if NDK ... the following is for the SDK ?>
+
+<?cs #
+    <div class="toggle-content special">
+    <p>The Android SDK has changed! If you've worked with the Android SDK before,
+    you will notice several important differences:</p>
+
+    <div class="toggle-content-toggleme" style="display:none">
+    <ul style="padding-bottom:.0;">
+    <li style="margin-top:.5em">The SDK downloadable package includes <em>only</em>
+    the latest version of the Android SDK Tools.</li>
+    <li>Once you've installed the SDK, you now use the Android SDK and AVD Manager
+    to download all of the SDK components that you need, such as Android platforms,
+    SDK add-ons, tools, and documentation. </li>
+    <li>The new approach is modular &mdash; you can install only the components you
+    need and update any or all components without affecting other parts of your
+    development environment.</li>
+    <li>In short, once you've installed the new SDK, you will not need to download
+    an SDK package again. Instead, you will use the Android SDK and AVD Manager to
+    keep your development environment up-to-date. </li>
+    </ul>
+    <p style="margin-top:0">If you are currently using the Android 1.6 SDK, you
+    do not need to install the new SDK, because your existing SDK already
+    includes the Android SDK and AVD Manager tool. To develop against Android
+    2.0.1, for example, you can just download the Android 2.0.1 platform (and
+    updated SDK Tools) into your existing SDK. Refer to <a
+    href="adding-components.html">Adding SDK Components</a>.</p>
+    </div>
+
+    <a href='#' class='toggle-content-button show' onclick="toggleContent(this,true);return false;">
+      <span>show more</span><span style='display:none'>show less</span>
+    </a>
+  </div>
+?>
+
+  <p>Welcome Developers! If you are new to the Android SDK, please read the steps below, for an
+overview of how to set up the SDK. </p>
+
+  <p>If you're already using the Android SDK, you should
+update to the latest tools or platform using the <em>Android SDK and AVD Manager</em>, rather than
+downloading a new SDK starter package. See <a
+href="{@docRoot}sdk/adding-components.html">Adding SDK Components</a>.</p>
+
+  <table class="download">
+    <tr>
+      <th>Platform</th>
+      <th>Package</th>
+      <th>Size</th>
+      <th>MD5 Checksum</th>
+  </tr>
+  <tr>
+    <td rowspan="2">Windows</td>
+    <td>
+  <a onclick="onDownload(this)" href="http://dl.google.com/android/<?cs var:sdk.win_download
+?>"><?cs var:sdk.win_download ?></a>
+    </td>
+    <td><?cs var:sdk.win_bytes ?> bytes</td>
+    <td><?cs var:sdk.win_checksum ?></td>
+  </tr>
+  <tr>
+    <!-- blank TD from Windows rowspan -->
+    <td>
+  <a onclick="onDownload(this)" href="http://dl.google.com/android/<?cs var:sdk.win_installer
+?>"><?cs var:sdk.win_installer ?></a> (Recommended)
+    </td>
+    <td><?cs var:sdk.win_installer_bytes ?> bytes</td>
+    <td><?cs var:sdk.win_installer_checksum ?></td>
+  </tr>
+  <tr class="alt-color">
+    <td>Mac OS X (intel)</td>
+    <td>
+  <a onclick="onDownload(this)" href="http://dl.google.com/android/<?cs var:sdk.mac_download
+?>"><?cs var:sdk.mac_download ?></a>
+    </td>
+    <td><?cs var:sdk.mac_bytes ?> bytes</td>
+    <td><?cs var:sdk.mac_checksum ?></td>
+  </tr>
+  <tr>
+    <td>Linux (i386)</td>
+    <td>
+  <a onclick="onDownload(this)" href="http://dl.google.com/android/<?cs var:sdk.linux_download
+?>"><?cs var:sdk.linux_download ?></a>
+    </td>
+    <td><?cs var:sdk.linux_bytes ?> bytes</td>
+    <td><?cs var:sdk.linux_checksum ?></td>
+  </tr>
+  <?cs if:adt.zip_download ?>
+  <tr class="alt-color">
+    <td>ADT Plugin for Eclipse <?cs var:adt.zip_version ?></td>
+    <td>
+  <a href="http://dl.google.com/android/<?cs var:adt.zip_download ?>"><?cs var:adt.zip_download ?></a>
+    </td>
+    <td><?cs var:adt.zip_bytes ?> bytes</td>
+    <td><?cs var:adt.zip_checksum ?></td>
+  </tr>
+  <?cs /if ?>
+  </table>
+
+
+<div id="next-steps" style="display:none">
+  <p><b><em><span id="filename"></span></em> is now downloading. Follow the steps below to
+get started.</b></p>
+</div>
+
+<script type="text/javascript">
+function onDownload(link) {
+  $("#filename").text($(link).html());
+  $("#next-steps").show();
+}
+</script>
+
+  <?cs /if ?>
+ <?cs /if ?>
+<?cs /if ?>
+
+<?cs if:android.whichdoc != "online" && sdk.preview ?>
+  <p>Welcome developers! The next release of the Android platform will be
+Android <?cs var:sdk.preview.version ?> and we are pleased to announce the
+availability of an early look SDK to give you a head-start on developing
+applications for it. </p>
+
+  <p>The Android <?cs var:sdk.preview.version ?> platform includes a variety of
+improvements and new features for users and developers. Additionally, the SDK
+itself introduces several new capabilities that enable you to develop
+applications more efficiently. See the <a
+href="http://developer.android.com/sdk/preview/features.html">Android
+<?cs var:sdk.preview.version ?> Highlights</a> document for a list of
+highlights.</p>
+<?cs /if ?>
+
+      <?cs call:tag_list(root.descr) ?>
+
+<?cs /if ?>
+</div><!-- end jd-content -->
+
+<?cs if:!sdk.redirect ?>
+     <?cs include:"footer.cs" ?>
+<?cs /if ?>
+
+</div><!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
+
+
+
diff --git a/build/tools/droiddoc/templates/assets/android-developer-core.css b/build/tools/droiddoc/templates/assets/android-developer-core.css
new file mode 100644 (file)
index 0000000..40ab2fd
--- /dev/null
@@ -0,0 +1,1195 @@
+/* file: android-developer-core.css
+   author: smain
+   date: september 2008
+   info: core developer styles (developer.android.com)
+*/
+
+
+/* RESET STYLES */
+
+html,body,div,h1,h2,h3,h4,h5,h6,p,img,
+dl,dt,dd,ol,ul,li,table,caption,tbody,
+tfoot,thead,tr,th,td,form,fieldset,
+embed,object,applet {
+  margin: 0;
+  padding: 0;
+  border: 0;
+}
+
+/* BASICS */
+
+html, body {
+  overflow:hidden; /* keeps scrollbar off IE */
+  background-color:#fff;
+}
+
+body {
+  font-family:arial,sans-serif;
+  color:#000;
+  font-size:13px;
+  color:#333;
+  background-image:url(images/bg_fade.jpg);
+  background-repeat:repeat-x;
+}
+
+a, a code {
+  color:#006699;
+}
+
+a:active,
+a:active code {
+  color:#f00;
+} 
+
+a:visited,
+a:visited code {
+  color:#006699;
+}
+
+input, select,
+textarea, option, label {
+  font-family:inherit;
+  font-size:inherit;
+  padding:0;
+  margin:0;
+  vertical-align:middle;
+}
+
+option {
+  padding:0 4px;
+}
+
+p {
+  padding:0;
+  margin:0 0 1em;
+}
+
+code, pre {
+  color:#007000;
+  font-family:monospace;
+  line-height:1em;
+}
+
+var {
+  color:#007000;
+  font-style:italic;
+}
+
+pre {
+  border:1px solid #ccc;
+  background-color:#fafafa;
+  padding:10px;
+  margin:0 0 1em 1em;
+  overflow:auto;
+  line-height:inherit; /* fixes vertical scrolling in webkit */
+}
+
+h1,h2,h3,h4,h5 {
+  margin:1em 0;
+  padding:0;
+}
+
+p,ul,ol,dl,dd,dt,li {
+  line-height:1.3em;
+}
+
+ul,ol {
+  margin:0 0 .8em;
+  padding:0 0 0 2em;
+}
+
+li {
+  padding:0 0 .5em;
+}
+
+dl {
+  margin:0 0 1em 0;
+  padding:0;
+}
+
+dt {
+  margin:0;
+  padding:0;
+}
+
+dd {
+  margin:0 0 1em;
+  padding:0 0 0 2em;
+}
+
+li p {
+  margin:.5em 0 0;
+}
+
+dd p {
+  margin:1em 0 0;
+}
+
+li pre, li table, li img {
+  margin:.5em 0 0 1em;
+}
+
+dd pre,
+#jd-content dd table,
+#jd-content dd img {
+  margin:1em 0 0 1em;
+}
+
+li ul,
+li ol,
+dd ul,
+dd ol {
+  margin:0;
+  padding: 0 0 0 2em;
+}
+
+li li,
+dd li {
+  margin:0;
+  padding:.5em 0 0;
+}
+
+dl dl,
+ol dl,
+ul dl {
+  margin:0 0 1em;
+  padding:0;
+}
+
+table {
+  font-size:1em;
+  margin:0 0 1em;
+  padding:0;
+  border-collapse:collapse;
+  border-width:0;
+  empty-cells:show;
+}
+
+td,th {
+  border:1px solid #ccc;
+  padding:6px 12px;
+  text-align:left;
+  vertical-align:top;
+  background-color:inherit;
+}
+
+th {
+  background-color:#dee8f1;
+}
+
+td > p:last-child {
+  margin:0;
+}
+
+hr.blue {
+  background-color:#DDF0F2;
+  border:none;
+  height:5px;
+  margin:20px 0 10px;
+}
+
+blockquote {
+  margin: 0 0 1em 1em;
+  padding: 0 4em 0 1em;
+  border-left:2px solid #eee;
+}
+/* LAYOUT */
+
+#body-content {
+  /* "Preliminary" watermark for preview releases and interim builds.
+  background:transparent url(images/preliminary.png) repeat scroll 0 0;  */
+  margin:0;
+  position:relative;
+  width:100%;
+}
+
+#header {
+  height: 114px;
+  position:relative;
+  z-index:100;
+  min-width:675px; /* min width for the tabs, before they wrap */
+  padding:0 10px;
+  border-bottom:3px solid #94b922;
+}
+
+#headerLeft{
+  padding: 25px 0 0;
+}
+
+#headerLeft img{
+  height:50px;
+  width:180px;
+}
+
+#headerRight {
+  position:absolute;
+  right:0;
+  top:0;
+  text-align:right;
+}
+
+/* Tabs in the header */
+
+#header ul {
+  list-style: none;
+  margin: 7px 0 0;
+  padding: 0;
+  height: 29px;
+}
+
+#header li {
+  float: left;
+  margin: 0px 2px 0px 0px;
+  padding:0;
+}
+
+#header li a {
+  text-decoration: none;
+  display: block;
+  background-image: url(images/bg_images_sprite.png);
+  background-position: 0 -58px;
+  background-repeat: no-repeat;
+  color: #666;
+  font-size: 13px;
+  font-weight: bold;
+  width: 94px;
+  height: 29px;
+  text-align: center;
+  margin: 0px;
+}
+
+#header li a:hover {
+  background-image: url(images/bg_images_sprite.png);
+  background-position: 0 -29px;
+  background-repeat: no-repeat;
+}
+
+#header li a span {
+  position:relative;
+  top:7px;
+}
+
+#header li a span+span {
+  display:none;
+}
+
+/* tab highlighting */
+
+.home #home-link a,
+.guide #guide-link a,
+.reference #reference-link a,
+.sdk #sdk-link a,
+.resources #resources-link a,
+.videos #videos-link a {
+  background-image: url(images/bg_images_sprite.png);
+  background-position: 0 0;
+  background-repeat: no-repeat;
+  color: #fff;
+  font-weight: bold;
+  cursor:default;
+}
+
+.home #home-link a:hover,
+.guide #guide-link a:hover,
+.reference #reference-link a:hover,
+.sdk #sdk-link a:hover,
+.resources #resources-link a:hover,
+.videos #videos-link  a:hover {
+  background-image: url(images/bg_images_sprite.png);
+  background-position: 0 0;
+}
+
+#headerLinks {
+  margin:10px 10px 0 0;
+  height:13px;
+  font-size: 11px;
+  vertical-align: top;
+}
+
+#headerLinks a {
+  color: #7FA9B5;
+}
+
+#headerLinks img {
+  vertical-align:middle;
+}
+
+#language {
+  margin:0 10px 0 4px;
+}
+
+#search {
+  height:45px;
+  margin:15px 10px 0 0;
+}
+
+/* MAIN BODY */
+
+#mainBodyFluid {
+  margin: 20px 10px;
+  color:#333;
+}
+
+#mainBodyFixed {
+  margin: 20px 10px;
+  color: #333;
+  width:930px;
+  position:relative;
+}
+
+#mainBodyFixed h3,
+#mainBodyFluid h3 {
+  color:#336666;
+  font-size:1.25em;
+  margin: 0em 0em 0em 0em;
+  padding-bottom:.5em;
+}
+
+#mainBodyFixed h2,
+#mainBodyFluid h2 {
+  color:#336666;
+  font-size:1.25em;
+  margin: 0;
+  padding-bottom:.5em;
+}
+
+#mainBodyFixed h1,
+#mainBodyFluid h1 {
+  color:#435A6E;
+  font-size:1.7em;
+  margin: 1em 0;
+}
+
+#mainBodyFixed .green,
+#mainBodyFluid .green,
+#jd-content .green {
+  color:#7BB026;
+  background-color:none;
+}
+
+#mainBodyLeft {
+  float: left;
+  width: 600px;
+  margin-right: 20px;
+  color: #333;
+  position:relative;
+}
+
+div.indent {
+  margin-left: 40px;
+  margin-right: 70px;
+}
+
+#mainBodyLeft p {
+  color: #333;
+  font-size: 13px;
+}
+
+#mainBodyLeft p.blue {
+  color: #669999;
+}
+
+#mainBodyLeft #communityDiv {
+  float: left;
+  background-image:url(images/bg_community_leftDiv.jpg);
+  background-repeat: no-repeat;
+  width: 581px;
+  height: 347px;
+  padding: 20px 0px 0px 20px;
+}
+
+#mainBodyRight {
+  float: left;
+  width: 300px;
+  color: #333;
+}
+
+#mainBodyRight p {
+  padding-right: 50px;
+  color: #333;
+}
+
+#mainBodyRight table {
+  width: 100%;
+}
+
+#mainBodyRight td {
+  border:0px solid #666;
+  padding:0px 5px;
+  text-align:left;
+}
+
+#mainBodyRight td p {
+  margin:0 0 1em 0;
+}
+
+#mainBodyRight .blueBorderBox {
+  border:5px solid #ddf0f2;
+  padding:18px 18px 18px 18px;
+  text-align:left;
+}
+
+#mainBodyFixed .seperator {
+  background-image:url(images/hr_gray_side.jpg);
+  background-repeat:no-repeat;
+  width: 100%;
+  float: left;
+  clear: both;
+}
+
+#mainBodyBottom {
+  float: left;
+  width: 100%;
+  clear:both;
+  color: #333;
+}
+
+#mainBodyBottom .seperator {
+  background-image:url(images/hr_gray_main.jpg);
+  background-repeat:no-repeat;
+  width: 100%;
+  float: left;
+  clear: both;
+}
+
+/* FOOTER */
+
+#footer {
+  float: left;
+  width:90%;
+  margin: 20px;
+  color: #aaa;
+  font-size: 11px;
+}
+
+#footer a {
+  color: #aaa;
+  font-size: 11px;
+}
+
+#footer a:hover {
+  text-decoration: underline;
+  color:#aaa;
+}
+
+#footerlinks {
+  margin-top:2px;
+}
+
+#footerlinks a,
+#footerlinks a:visited {
+  color:#006699;
+}
+
+/* SEARCH FILTER */
+
+#search_autocomplete {
+  color:#aaa;
+}
+
+#search-button {
+  display:inline;
+}
+
+#search_filtered_div {
+  position:absolute;
+  margin-top:-1px;
+  z-index:101;
+  border:1px solid #BCCDF0;
+  background-color:#fff;
+}
+
+#search_filtered {
+  min-width:100%;
+}
+#search_filtered td{
+  background-color:#fff;
+  border-bottom: 1px solid #669999;
+  line-height:1.5em;
+}
+
+#search_filtered .jd-selected {
+  background-color: #94b922;
+  cursor:pointer;
+}
+#search_filtered .jd-selected,
+#search_filtered .jd-selected a {
+  color:#fff;
+}
+
+.no-display {
+  display: none;
+}
+
+.jd-autocomplete {
+  font-family: Arial, sans-serif;
+  padding-left: 6px;
+  padding-right: 6px;
+  padding-top: 1px;
+  padding-bottom: 1px;
+  font-size: 0.81em;
+  border: none;
+  margin: 0;
+  line-height: 1.05em;
+}
+
+.show-row {
+  display: table-row;
+}
+.hide-row {
+  display: hidden;
+}
+
+/* SEARCH */
+
+/* restrict global search form width */
+#searchForm {
+  width:350px;
+}
+
+#searchTxt {
+  width:200px;
+}
+
+/* disable twiddle and size selectors for left column */
+#leftSearchControl div {
+  width: 100%;
+}
+
+#leftSearchControl .gsc-twiddle {
+  background-image : none;
+}
+
+#leftSearchControl td, #searchForm td {
+  border: 0px solid #000;
+}
+
+#leftSearchControl .gsc-resultsHeader .gsc-title {
+  padding-left : 0px;
+  font-weight : bold;
+  font-size : 13px;
+  color:#006699;
+  display : none;
+}
+
+#leftSearchControl .gsc-resultsHeader div.gsc-results-selector {
+  display : none;
+}
+
+#leftSearchControl .gsc-resultsRoot {
+  padding-top : 6px;
+}
+
+#leftSearchControl div.gs-visibleUrl-long {
+  display : block;
+  color:#006699;
+}
+
+.gsc-webResult div.gs-visibleUrl-short,
+table.gsc-branding,
+.gsc-clear-button {
+  display : none;
+}
+
+.gsc-cursor-box .gsc-cursor div.gsc-cursor-page,
+.gsc-cursor-box .gsc-trailing-more-results a.gsc-trailing-more-results,
+#leftSearchControl a,
+#leftSearchControl a b {
+  color:#006699;
+}
+
+.gsc-resultsHeader {
+  display: none;
+}
+
+/* Disable built in search forms */
+.gsc-control form.gsc-search-box {
+  display : none;
+}
+table.gsc-search-box {
+  margin:6px 0 0 0;
+  border-collapse:collapse;
+}
+
+td.gsc-input {
+  padding:0 2px;
+  width:100%;
+  vertical-align:middle;
+}
+
+input.gsc-input {
+  border:1px solid #BCCDF0;
+  width:99%;
+  padding-left:2px;
+  font-size:.95em;
+}
+
+td.gsc-search-button {
+  text-align: right;
+  padding:0;
+  vertical-align:top;
+}
+
+#search-button {
+  margin:0 0 0 2px;
+  font-size:11px;
+}
+
+/* search result tabs */
+
+#doc-content .gsc-control {
+  position:relative;
+}
+
+#doc-content .gsc-tabsArea {
+  position:relative;
+  white-space:nowrap;
+}
+
+#doc-content .gsc-tabHeader {
+  padding: 3px 6px;
+  position:relative;
+}
+
+#doc-content .gsc-tabHeader.gsc-tabhActive {
+  border-top: 2px solid #94B922;
+}
+
+#doc-content h2#searchTitle {
+  padding:0;
+}
+
+#doc-content .gsc-resultsbox-visible {
+  padding:1em 0 0 6px;
+}
+
+/* CAROUSEL */
+
+#homeMiddle {
+  padding: 0px 0px 0px 0px;
+  float: left;
+  width: 584px;
+  height: 627px;
+  position:relative;
+}
+
+#topAnnouncement {
+  background:url(images/home/bg_home_announcement.png) no-repeat 0 0;
+}
+  
+#homeTitle {
+  padding:15px 15px 0;
+  height:30px;
+}
+
+#homeTitle h2 {
+  padding:0;
+}
+
+#announcement-block {
+  padding:0 15px 0;
+  overflow:hidden;
+  background: url(images/hr_gray_side.jpg) no-repeat 15px 0;
+  zoom:1;
+}
+
+#announcement-block>* {
+  padding:15px 0 0;
+}
+
+#announcement-block img {
+  float:left;
+  margin:0 30px 0 0;
+}
+
+#announcement {
+  float:left;
+  margin:0;
+}
+
+#carousel {
+  background:url(images/home/bg_home_carousel.png) no-repeat 0 0;
+  position:relative;
+  height:400px;
+}
+
+#carouselMain {
+  background: url(images/home/bg_home_carousel_board.png) 0 0 no-repeat;
+  height:auto;
+  padding: 25px 21px 0;
+  overflow:hidden;
+  position:relative;
+  zoom:1; /*IE6*/
+}
+
+#carouselMain img {
+  margin:0;
+}
+
+#carouselMain .bulletinDesc h3 {
+  margin:0;
+  padding:0;
+}
+
+#carouselMain .bulletinDesc p {
+  margin:0;
+  padding:0.7em 0 0;
+}
+
+#carouselWheel {
+  background: url(images/home/bg_home_carousel_wheel.png) 0 0 no-repeat;
+  padding-top:40px;
+  height:150px;
+}
+
+.clearer { clear:both; }
+
+a#arrow-left, a#arrow-right {
+  float:left;
+  width:42px;
+  height:42px;
+  background-image:url(images/home/carousel_buttons_sprite.png);
+  background-repeat:no-repeat;
+}
+a#arrow-left {
+  margin:35px 3px 0 10px;
+}
+a#arrow-right {
+  margin:35px 10px 0 0;
+}
+a.arrow-left-off,
+a#arrow-left.arrow-left-off:hover {
+  background-position:0 0;
+}
+a.arrow-right-off,
+a#arrow-right.arrow-right-off:hover {
+  background-position:-42px 0;
+}
+a#arrow-left:hover {
+  background-position:0 -42px;
+}
+a#arrow-right:hover {
+  background-position:-42px -42px;
+}
+a.arrow-left-on {
+  background-position:0 0;
+}
+a.arrow-right-on {
+  background-position:-42px 0;
+}
+a.arrow-right-off,
+a.arrow-left-off {
+  cursor:default;
+}
+
+.app-list-container {
+  margin:0 20px;
+  position:relative;
+  width:100%;
+}
+
+div#list-clip {
+  height:110px;
+  width:438px;
+  overflow:hidden;
+  position:relative;
+  float:left;
+}
+
+div#app-list {
+  left:0;
+  z-index:1;
+  position:absolute;
+  margin:11px 0 0;
+  _margin-top:13px;
+  width:1000%;
+}
+
+#app-list a {
+  display:block;
+  float:left;
+  height:90px;
+  width:90px;
+  margin:0 24px 0;
+  padding:3px;
+  background:#99cccc;
+  -webkit-border-radius:7px;
+  -moz-border-radius:7px;
+  border-radius:7px;
+  text-decoration:none;
+  text-align:center;
+  font-size:11px;
+  line-height:11px;
+}
+
+#app-list a span {
+  position:relative;
+  top:-4px;
+}
+
+#app-list img {
+  width:90px;
+  height:70px;
+  margin:0;
+}
+
+#app-list a.selected,
+#app-list a:active.selected,
+#app-list a:hover.selected {
+  background:#A4C639;
+  color:#fff;
+  cursor:default;
+  text-decoration:none;
+}
+
+#app-list a:hover,
+#app-list a:active {
+  background:#ff9900;
+}
+
+#app-list a:hover span,
+#app-list a:active span {
+  text-decoration:underline;
+}
+
+#droid-name {
+  padding-top:.5em;
+  color:#666;
+  padding-bottom:.25em;
+}
+
+/*IE6*/
+* html #app-list a { zoom: 1; margin:0 24px 0 15px;}
+
+* html #list-clip {
+  width:430px !important;
+}
+
+/*carousel bulletin layouts*/
+/*460px width*/
+/*185px height*/
+.img-left {
+  float:left;
+  width:230px;
+  overflow:hidden;
+  padding:8px 0 8px 8px;
+}
+.desc-right {
+  float:left;
+  width:270px;
+  padding:10px;
+}
+.img-right {
+  float:right;
+  width:220px;
+  overflow:hidden;
+  padding:8px 8px 8px 0;
+}
+.desc-left {
+  float:right;
+  width:280px;
+  padding:10px;
+  text-align:right;
+}
+.img-top {
+  padding:20px 20px 0;
+}
+.desc-bottom {
+  padding:10px;
+}
+
+
+/* VIDEO PAGE */
+
+#mainBodyLeft.videoPlayer {
+  width:570px;
+}
+
+#mainBodyRight.videoPlayer {
+  width:330px;
+}
+
+/* player */
+
+#videoPlayerBox {
+  background-color: #DAF3FC;
+  border-radius:7px;
+  -moz-border-radius:7px;
+  -webkit-border-radius:7px;
+  width:530px;
+  padding:20px;
+  border:1px solid #d3ecf5;
+  box-shadow:2px 3px 1px #eee;
+  -moz-box-shadow:2px 3px 1px #eee;
+  -webkit-box-shadow:2px 3px 1px #eee;
+}
+
+#videoBorder {
+  background-color: #FFF;
+  min-height:399px;
+  height:auto !important;
+  border:1px solid #ccdada;
+  border-radius:7px 7px 0 0;
+  -moz-border-radius:7px 7px 0 0;
+  -webkit-border-top-left-radius:7px;
+  -webkit-border-top-right-radius:7px;
+}
+
+#videoPlayerTitle {
+  width:500px;
+  padding:15px 15px 0;
+}
+
+#videoPlayerTitle h2 {
+  font-weight:bold;
+  font-size:1.2em;
+  color:#336666;
+  margin:0;
+  padding:0;
+}
+
+#objectWrapper {
+  padding:15px 15px;
+  height:334px;
+  width:500px;
+}
+
+/* playlist tabs */
+
+ul#videoTabs {
+  list-style-type:none;
+  padding:0;
+  clear:both;
+  margin:0;
+  padding: 20px 0 0 15px;
+  zoom:1; /* IE7/8, otherwise top-padding is double */
+}
+
+ul#videoTabs li {
+  display:inline;
+  padding:0;
+  margin:0 3px 0 0;
+  line-height:2em;
+}
+
+ul#videoTabs li a {
+  border-radius:7px 7px 0 0;
+  -moz-border-radius:7px 7px 0 0;
+  -webkit-border-top-left-radius:7px;
+  -webkit-border-top-right-radius:7px;
+  background:#95c0d0;
+  color:#fff;
+  text-decoration:none;
+  padding:.45em 1.5em;
+  font-weight:bold;
+}
+
+ul#videoTabs li.selected a {
+  font-weight:bold;
+  text-decoration:none;
+  color:#555;
+  background:#daf3fc;
+  border-bottom:1px solid #daf3fc;
+}
+
+ul#videoTabs li:hover a {
+  background:#85acba;
+}
+
+ul#videoTabs li.selected:hover a {
+  background:#daf3fc;
+}
+
+/* playlists */
+
+#videos {
+  background:#daf3fc;
+  margin-bottom:1.5em;
+  padding:15px;
+  border-radius:5px;
+  -moz-border-radius:5px;
+  -webkit-border-radius:5px;
+  box-shadow:2px 3px 1px #eee;
+  -moz-box-shadow:2px 3px 1px #eee;
+  -webkit-box-shadow:2px 3px 1px #eee;
+}
+
+#videos div {
+  display:none;
+}
+
+#videos div.selected {
+  display:block;
+}
+
+ul.videoPreviews {
+  list-style:none;
+  padding:0;
+  margin:0;
+  zoom:1; /* IE, otherwise, layout doesn't update when showing 'more' */
+}
+
+ul.videoPreviews li {
+  margin:0 0 5px;
+  padding:0;
+  overflow:hidden;
+  position:relative;
+}
+
+#mainBodyFixed ul.videoPreviews h3 {
+  font-size: 12px;
+  margin:0 0 1em 130px;
+  padding:0;
+  font-weight:bold;
+  color:inherit;
+}
+
+ul.videoPreviews a {
+  margin:1px;
+  padding:10px;
+  text-decoration:none;
+  height:90px;
+  display:block;
+  border-radius:5px;
+  -moz-border-radius:5px;
+  -webkit-border-radius:5px;
+  background-color:transparent;
+}
+
+ul.videoPreviews a:hover {
+  background-color:#FFF;
+  border:none; /* IE8, otherwise, bg doesn't work */
+}
+
+ul.videoPreviews a.selected {
+  background-color: #FF9900;
+}
+
+ul.videoPreviews img {
+  float:left;
+  clear:left;
+  margin:0;
+}
+
+ul.videoPreviews h3 {
+  font-size:12px;
+  font-weight:bold;
+  text-decoration:none;
+  margin:0 0 1em 130px;
+  padding:0;
+}
+
+ul.videoPreviews p {
+  font-size: 12px;
+  text-decoration:none;
+  margin:0 0 1.2em 130px;
+}
+
+ul.videoPreviews p.full {
+  display:none;
+}
+
+ul.videoPreviews span.more {
+  padding:0 0 0 12px;
+  background:url(images/arrow_bluelink_down.png) 0 2px no-repeat;
+}
+
+ul.videoPreviews span.less {
+  padding:0 0 0 12px;
+  background:url(images/arrow_bluelink_up.png) 0 2px no-repeat;
+  display:none;
+}
+
+ul.videoPreviews p.toggle {
+  position:absolute;
+  margin:0;
+  margin-top:-23px; /* instead of bottom:23px, because IE won't do it correctly */
+  left:140px;
+}
+
+ul.videoPreviews p.toggle a {
+  height:auto;
+  margin:0;
+  padding:0;
+  zoom:1; /* IE6, otherwise the margin considers the img on redraws */
+}
+
+ul.videoPreviews p.toggle a:hover {
+  text-decoration:underline;
+  background:transparent; /* IE6, otherwise it inherits white */
+}
+
+/* featured videos */
+
+#mainBodyRight h2 {
+  padding:0 0 5px;
+}
+
+#mainBodyRight ul.videoPreviews {
+  margin:10px 0 0;
+}
+
+#mainBodyRight ul.videoPreviews li {
+  font-size:11px;
+  line-height:13px;
+  margin:0 0 5px;
+  padding:0;
+}
+
+#mainBodyRight ul.videoPreviews h3 {
+  padding:0;
+  margin:0;
+}
+
+#mainBodyRight ul.videoPreviews a {
+  text-decoration:none;
+  height:108px;
+  border:1px solid #FFF;
+}
+
+#mainBodyRight ul.videoPreviews a:hover {
+  border:1px solid #CCDADA;
+}
+
+#mainBodyRight ul.videoPreviews a.selected {
+  border:1px solid #FFF;
+}
+
+#mainBodyRight ul.videoPreviews p {
+  line-height:1.2em;
+  padding:0;
+  margin:4px 0 0 130px;
+}
+
+#mainBodyRight ul.videoPreviews img {
+  margin-top:5px;
+}
+
+/* Pretty printing styles. Used with prettify.js. */
+
+.str { color: #080; }
+.kwd { color: #008; }
+.com { color: #800; }
+.typ { color: #606; }
+.lit { color: #066; }
+.pun { color: #660; }
+.pln { color: #000; }
+dl.tag-list dt code,
+.tag { color: #008; }
+dl.atn-list dt code,
+.atn { color: #828; }
+.atv { color: #080; }
+.dec { color: #606; }
+
+@media print {
+  .str { color: #060; }
+  .kwd { color: #006; font-weight: bold; }
+  .com { color: #600; font-style: italic; }
+  .typ { color: #404; font-weight: bold; }
+  .lit { color: #044; }
+  .pun { color: #440; }
+  .pln { color: #000; }
+  .tag { color: #006; font-weight: bold; }
+  .atn { color: #404; }
+  .atv { color: #060; }
+}
diff --git a/build/tools/droiddoc/templates/assets/android-developer-docs-devguide.css b/build/tools/droiddoc/templates/assets/android-developer-docs-devguide.css
new file mode 100644 (file)
index 0000000..d8bd3b3
--- /dev/null
@@ -0,0 +1,19 @@
+
+@import url("android-developer-docs.css");
+
+/* Page title */
+
+#jd-header h1 {
+  padding: 8px 0 0 0;
+}
+
+/* Page content container */
+
+#jd-header table {
+margin: 0 0 1em 1em;
+}
+
+#jd-content table table,
+#jd-content table img {
+  margin:1em 0;
+}
\ No newline at end of file
diff --git a/build/tools/droiddoc/templates/assets/android-developer-docs.css b/build/tools/droiddoc/templates/assets/android-developer-docs.css
new file mode 100644 (file)
index 0000000..a574237
--- /dev/null
@@ -0,0 +1,1365 @@
+/* file: android-developer-docs.css
+   author: smain
+   date: september 2008
+   info: developer doc styles (developer.android.com)
+*/
+
+@import url("android-developer-core.css");
+
+#title {
+  border-bottom: 4px solid #ccc;
+  display:none;
+}
+
+#title h1 {
+  color:#336666;
+  margin:0;
+  padding: 5px 10px;
+  font-size: 1em;
+  line-height: 15px;
+}
+
+#title h1 .small{
+  color:#000;
+  margin:0;
+  font-size: 13px;
+  padding:0 0 0 15px;
+}
+
+/* SIDE NAVIGATION */
+
+#side-nav {
+  padding:0 6px 0 0;
+  background-color: #fff;
+  font-size:12px;
+}
+
+#resize-packages-nav {
+/* keeps the resize handle below the h-scroll handle */
+  height:270px;
+  overflow:hidden;
+  max-height:100%;
+}
+
+#packages-nav {
+  height:270px;
+  max-height:inherit;
+  position:relative;
+  overflow:auto;
+}
+
+#classes-nav,
+#devdoc-nav {
+  overflow:auto;
+  position:relative;
+}
+
+#side-nav ul {
+  list-style: none;
+  margin: 0;
+  padding:5px 0;
+}
+
+#side-nav ul ul {
+  margin: .35em 0 0 0;
+  padding: 0;
+}
+
+#side-nav li {
+  padding:0;
+  line-height:16px;
+  white-space:nowrap;
+  zoom:1;
+}
+
+#side-nav li h2 {
+  font-size:12px;
+  font-weight: bold;
+  margin:.5em 0 0 0;
+  padding: 3px 0 1px 9px;
+}
+
+#side-nav li a {
+  text-decoration:none;
+  padding: 0 0 0 18px;
+  zoom:1;
+}
+
+#side-nav li a span+span {
+  display:none;
+}
+
+#side-nav li a:hover {
+  text-decoration:underline;
+}
+
+#side-nav li a+a {
+  padding: 0;
+}
+/*second level (nested) list*/
+#side-nav li li li a {
+  padding: 0 0 0 28px;
+}
+/*third level (nested) list*/
+#side-nav li li li li a {
+  padding: 0 0 0 38px;
+}
+
+#side-nav .selected {
+  background-color: #435a6e;
+  color: #fff;
+  font-weight:bold;
+}
+
+#side-nav .selected a {
+  color: #fff;
+  text-decoration:none;
+}
+
+#side-nav strong {
+  display:block;
+}
+
+#side-nav .toggle-list .toggle-img {
+  margin:0;
+  padding:0;
+  position:absolute;
+  top:0;
+  left:0;
+  height:16px;
+  width:15px;
+  outline-style:none;
+}
+/* second-level toggle */
+#side-nav .toggle-list .toggle-list .toggle-img {
+  left:10px;
+}
+
+#side-nav .closed .toggle-img,
+#side-nav .open .closed .toggle-img {
+  background:url('images/triangle-closed-small.png') 7px 4px no-repeat;
+}
+#side-nav .open .toggle-img {
+  background:url('images/triangle-opened-small.png') 7px 4px no-repeat;
+}
+
+#side-nav .toggle-list {
+  position:relative;
+}
+
+#side-nav .toggle-list ul {
+  margin:0;
+  display:none;
+}
+
+#side-nav .toggle-list div {
+  display:block;
+}
+
+#index-links .selected {
+  background-color: #fff;
+  color: #000;
+  font-weight:normal;
+  text-decoration:none;
+}
+
+#index-links {
+  padding:7px 0 4px 10px;
+}
+
+/* nav tree */
+
+#nav-tree ul {
+  padding:5px 0 1.5em;
+}
+
+#side-nav #nav-tree ul li a,
+#side-nav #nav-tree ul li span.no-children {
+  padding: 0 0 0 0;
+  margin: 0;
+}
+
+#nav-tree .plus {
+  margin: 0 3px 0 0;
+}
+
+#nav-tree ul ul {
+  list-style: none;
+  margin: 0;
+  padding: 0 0 0 0;
+}
+
+#nav-tree ul li {
+  margin: 0;
+  padding: 0 0 0 0;
+  white-space: nowrap;
+}
+
+#nav-tree .children_ul {
+  margin:0;
+}
+
+#nav-tree a.nolink {
+  color: black;
+  text-decoration: none;
+}
+
+#nav-tree span.label {
+  width: 100%;
+}
+
+#nav-tree {
+  overflow-x: auto;
+  overflow-y: scroll;
+}
+
+#nav-swap {
+  font-size:10px;
+  line-height:10px;
+  margin-left:1em;
+  text-decoration:none;
+  display:block;
+}
+
+#tree-link {
+
+}
+
+/* DOCUMENT BODY */
+
+#doc-content {
+  overflow:auto;
+}
+
+#jd-header {
+  background-color: #E2E2E2;
+  padding: 7px 15px;
+}
+
+#jd-header h1 {
+  margin: 0 0 10px;
+  font-size:1.7em;
+}
+
+#jd-header .crumb {
+  font-size:.9em;
+  line-height:1em;
+  color:#777;
+}
+
+#jd-header .crumb a,
+#jd-header .crumb a:visited {
+  text-decoration:none;
+  color:#777;
+}
+
+#jd-header .crumb a:hover {
+  text-decoration:underline;
+}
+
+#jd-header table {
+  margin:0;
+  padding:0;
+}
+
+#jd-header td {
+  border:none;
+  padding:0;
+  vertical-align:top;
+}
+
+#jd-header.guide-header {
+  background-color:#fff;
+  color:#435a6e;
+  height:50px;
+}
+
+#jd-descr {
+  position:relative;
+}
+
+/* summary tables for reference pages */
+.jd-sumtable {
+  margin: .5em 1em 1em 1em;
+  width:95%; /* consistent table widths; within IE's quirks */
+  font-size:.9em;
+}
+
+.jd-sumtable a {
+  text-decoration:none;
+}
+
+.jd-sumtable a:hover {
+  text-decoration:underline;
+}
+
+/* the link inside a sumtable for "Show All/Hide All" */
+.toggle-all {
+  display:block;
+  float:right;
+  font-weight:normal;
+  font-size:0.9em;
+}
+
+/* adjustments for in/direct subclasses tables */
+.jd-sumtable-subclasses {
+  margin: 1em 0 0 0;
+  max-width:968px;
+}
+
+/* extra space between end of method name and open-paren */
+.sympad {
+  margin-right: 2px;
+}
+
+/* right alignment for the return type in sumtable */
+.jd-sumtable .jd-typecol {
+  text-align:right;
+}
+
+/* adjustments for the expando table-in-table */
+.jd-sumtable-expando {
+  margin:.5em 0;
+  padding:0;
+}
+
+/* a div that holds a short description */
+.jd-descrdiv {
+  padding:3px 1em 0 1em;
+  margin:0;
+  border:0;
+}
+
+/* page-top-right container for reference pages (holds
+links to summary tables) */
+#api-info-block {
+  font-size:.8em;
+  padding:6px 10px;
+  font-weight:normal;
+  float:right;
+  text-align:right;
+  color:#999;
+  max-width:70%;
+}
+
+#api-level-toggle {
+  padding:0 10px;
+  font-size:11px;
+  float:right;
+}
+
+#api-level-toggle label.disabled {
+  color:#999;
+}
+
+div.api-level {
+  font-size:.8em;
+  font-weight:normal;
+  color:#999;
+  float:right;
+  padding:0 7px 0;
+  margin-top:-25px;
+}
+
+#api-info-block div.api-level {
+  font-size:1.3em;
+  font-weight:bold;
+  float:none;
+  color:#444;
+  padding:0;
+  margin:0;
+}
+
+/* Force link colors for IE6 */
+div.api-level a {
+  color:#999;
+}
+#api-info-block div.api-level a:link {
+  color:#444;
+}
+#api-level-toggle a {
+  color:#999;
+}
+
+div#naMessage {
+  display:none;
+  width:555px;
+  height:0;
+  margin:0 auto;
+}
+
+div#naMessage div {
+  width:450px;
+  position:fixed;
+  margin:50px 0;
+  padding:4em 4em 3em;
+  background:#FFF;
+  background:rgba(255,255,255,0.7);
+  border:1px solid #dddd00;
+}
+/* IE6 can't position fixed */
+* html div#naMessage div { position:absolute; }
+
+div#naMessage strong {
+  font-size:1.1em;
+}
+
+.absent,
+.absent a:link,
+.absent a:visited,
+.absent a:hover,
+.absent * {
+  color:#bbb !important;
+  cursor:default !important;
+  text-decoration:none !important;
+}
+
+#api-level-toggle a,
+.api-level a {
+  color:inherit;
+  text-decoration:none;
+}
+
+#api-level-toggle a:hover,
+.api-level a:hover {
+  color:inherit;
+  text-decoration:underline !important;
+  cursor:pointer !important;
+}
+
+#side-nav li.absent.selected,
+#side-nav li.absent.selected *,
+#side-nav div.label.absent.selected,
+#side-nav div.label.absent.selected * {
+  background-color:#eaeaea !important;
+}
+/* IE6 quirk (won't chain classes, so just keep background blue) */
+* html #side-nav li.selected,
+* html #side-nav li.selected *,
+* html #side-nav div.label.selected,
+* html #side-nav div.label.selected * {
+  background-color: #435a6e !important;
+}
+
+
+.absent h4.jd-details-title,
+.absent h4.jd-details-title * {
+  background-color:#f6f6f6 !important;
+}
+
+.absent img {
+  opacity: .3;
+  filter: alpha(opacity=30);
+  -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";
+}
+
+
+/* applies to a div containing links to summary tables */
+.sum-details-links {
+  padding:0;
+  font-weight:normal;
+}
+
+.sum-details-links a {
+  text-decoration:none;
+}
+
+.sum-details-links a:hover {
+  text-decoration:underline;
+}
+
+
+/* inheritance table */
+.jd-inheritance-table {
+  border-spacing:0;
+  margin:0;
+  padding:0;
+  font-size:.9em;
+}
+.jd-inheritance-table td {
+  border: none;
+  margin: 0;
+  padding: 0;
+}
+.jd-inheritance-table .jd-inheritance-space {
+  font-weight:bold;
+  width:1em;
+}
+.jd-inheritance-table .jd-inheritance-interface-cell {
+  padding-left: 17px;
+}
+
+#jd-content {
+  padding: 18px 15px;
+}
+
+hr {
+  background-color:#ccc;
+  border-color:#fff;
+  margin:2em 0 1em;
+}
+
+/* DOC CLASSES */
+
+#jd-content h1 {
+/*sdk page*/
+  font-size:1.6em;
+  color:#336666;
+  margin:0 0 .5em;
+}
+
+#jd-content h2 {
+  font-size:1.45em;
+  color:#111;
+  border-top:2px solid #ccc;
+  padding: .5em 0 0;
+  margin: 2em 0 1em 0;
+}
+
+#jd-content h3 {
+  font-size:1.2em;
+  color:#222;
+  padding: .75em 0 .65em 0;
+  margin:0;
+}
+
+#jd-content h4 {
+  font-size:1.1em;
+  margin-bottom:.5em;
+  color:#222;
+}
+
+#jd-content .small-header {
+  font-size:1em;
+  color:#000;
+  font-weight:bold;
+  border:none;
+  padding:0;
+  margin:1em 0 .5em;
+  position:inherit;
+}
+
+#jd-content table {
+  margin: 0 0 1em 1em;
+}
+
+#jd-content img {
+  margin: 0 0 1em 1em;
+}
+
+#jd-content li img,
+#jd-content dd img {
+  margin:.5em 0 0 1em;
+}
+
+.nolist {
+  list-style:none;
+  padding:0;
+  margin:0 0 1em 1em;
+}
+
+.nolist li {
+  padding:0 0 2px;
+  margin:0;
+}
+
+h4 .normal {
+  font-size:.9em;
+  font-weight:normal;
+}
+
+.caps {
+  font-variant:small-caps;
+  font-size:1.2em;
+}
+
+dl.tag-list dl.atn-list {
+  padding:0 0 0 2em;
+}
+
+.jd-details {
+/*  border:1px solid #669999;
+  padding:4px; */
+  margin:0 0 1em;
+}
+
+/* API reference: a container for the
+.tagdata blocks that make up the detailed
+description */
+.jd-details-descr {
+  padding:0;
+  margin:.5em .25em;
+}
+
+/* API reference: a block containing
+a detailed description, a params table,
+seealso list, etc */
+.jd-tagdata {
+  margin:.5em 1em;
+}
+
+.jd-tagdata p {
+  margin:0 0 1em 1em;
+}
+
+/* API reference: adjustments to
+the detailed description block */
+.jd-tagdescr {
+  margin:.25em 0 .75em 0;
+  line-height:1em;
+}
+
+.jd-tagdescr p {
+  margin:.5em 0;
+  padding:0;
+
+}
+
+.jd-tagdescr ol,
+.jd-tagdescr ul {
+  margin:0 2.5em;
+  padding:0;
+}
+
+.jd-tagdescr table,
+.jd-tagdescr img {
+  margin:.25em 1em;
+}
+
+.jd-tagdescr li {
+margin:0 0 .25em 0;
+padding:0;
+}
+
+/* API reference: heading marking
+the details section for constants,
+attrs, methods, etc. */
+h4.jd-details-title {
+  font-size:1.15em;
+  background-color: #E2E2E2;
+  margin:1.5em 0 .6em;
+  padding:3px 95px 3px 3px; /* room for api-level */
+}
+
+h4.jd-tagtitle {
+  margin:0;
+}
+
+/* API reference: heading for "Parameters", "See Also", etc.,
+in details sections */
+h5.jd-tagtitle {
+  margin:0 0 .25em 0;
+  font-size:1em;
+}
+
+.jd-tagtable {
+  margin:0;
+}
+
+.jd-tagtable td,
+.jd-tagtable th {
+  border:none;
+  background-color:#fff;
+  vertical-align:top;
+  font-weight:normal;
+  padding:2px 10px;
+}
+
+.jd-tagtable th {
+  font-style:italic;
+}
+
+#jd-content table h2 {
+  background-color: #d6d6d6;
+  font-size: 1.1em;
+  margin:0 0 10px;
+  padding:5px;
+  left:0;
+  width:auto;
+}
+
+div.special {
+  padding: .5em 1em 1em 1em;
+  margin: 0 0 1em;
+  background-color: #DAF3FC;
+  border:1px solid #d3ecf5;
+  border-radius:5px;
+  -moz-border-radius:5px;
+  -webkit-border-radius:5px;
+}
+
+.toggle-content-toggleme {
+  display:none;
+}
+
+.toggle-content-button {
+  font-size:.9em;
+  line-height:.9em;
+  text-decoration:none;
+  position:relative;
+  top:5px;
+}
+
+.toggle-content-button:hover {
+  text-decoration:underline;
+}
+
+div.special p {
+  margin: .5em 0 0 0;
+}
+
+div.special ol {
+  margin: 0;
+}
+
+div.special ol li {
+  margin: 0;
+  padding: 0;
+}
+
+#jd-content div.special h2,
+#jd-content div.special h3 {
+  color:#669999;
+  font-size:1.2em;
+  border:none;
+  margin:0 0 .5em;
+  padding:0;
+}
+
+p.note, p.caution, p.warning {
+  margin: 1em;
+  padding: 0 0 0 .5em;
+  border-left: 4px solid;
+}
+
+p.special-note {
+  background-color:#EBF3DB;
+  padding:10px 20px;
+  margin:0 0 1em;
+}
+
+p.note {
+ border-color: #99aacc;
+}
+
+p.warning {
+  border-color: #aa0033;
+}
+
+p.caution {
+  border-color: #ffcf00;
+}
+
+p.warning b, p.warning strong {
+  font-weight: bold;
+}
+
+li p.note, li p.warning {
+  margin: .5em 0 0 0;
+  padding: .2em .5em .2em .9em;
+}
+
+dl.xml dt {
+  font-variant:small-caps;
+  font-size:1.2em;
+}
+
+dl.xml dl {
+  padding:0;
+}
+
+dl.xml dl dt {
+  font-variant:normal;
+  font-size:1em;
+}
+
+.listhead li {
+  font-weight: bold;
+}
+
+.listhead li *, /*ie*/.listhead li li {
+  font-weight: normal;
+}
+
+ol.no-style,
+ul.no-style {
+  list-style:none;
+  padding-left:1em;
+}
+
+.new {
+  font-size: .78em;
+  font-weight: bold;
+  color: #ff3d3d;
+  text-decoration: none;
+  vertical-align:top;
+  line-height:.9em;
+}
+
+pre.classic {
+  background-color:transparent;
+  border:none;
+  padding:0;
+}
+
+p.img-caption {
+  margin: -0.5em 0 1em 1em; /* matches default img left-margin */
+}
+
+div.figure {
+  float:right;
+  clear:right;
+  margin:1em 0 0 0;
+  padding:0 0 0 3em;
+  background-color:#fff;
+  /* width must be defined w/ an inline style matching the image width */
+}
+
+#jd-content
+div.figure img {
+  margin: 0 0 1em;
+}
+
+div.figure p.img-caption {
+  margin: -0.5em 0 1em 0;
+}
+
+p.table-caption {
+  margin: 0 0 0.5em 1em; /* matches default table left-margin */
+}
+
+/* BEGIN quickview sidebar element styles */
+
+#qv-wrapper {
+  float: right;
+  width:310px; /* +35px padding */
+  background-color:#fff;
+  margin:-48px 0 2px 0;
+  padding:0 0 20px 35px;
+}
+
+#qv {
+  background-color:#fff;
+  border:4px solid #dee8f1;
+  margin:0;
+  padding:0 5px 5px;
+  width:292px; /* +10px padding; +8px border */
+  font-size:.9em;
+}
+
+#qv ol {
+  list-style:none;
+  padding: 0;
+}
+
+#qv ol ol{
+  list-style:none;
+  padding: 0 0 0 12px;
+  margin:0;
+}
+
+#qv ul {
+  padding: 0 10px 0 2em;
+}
+
+#qv li {
+  padding: 0 10px 3px;
+  line-height: 1.2em;
+}
+
+#qv li li {
+  padding: 3px 10px 0;
+}
+
+#qv ul li {
+  padding: 0 10px 0 0;
+}
+
+#qv li.selected a {
+  color:#555;
+  text-decoration:none;
+}
+
+#qv a,
+#qv a code {
+  color:#cc6600;
+}
+
+#qv p {
+  margin:8px 0 0;
+  padding:0 10px;
+}
+
+#qv-extra #rule {
+  padding: 0 10px;
+  margin: 0;
+}
+
+#qv-sub-rule {
+  padding: 6px 20px;
+  margin: 0;
+}
+
+#qv-sub-rule p {
+  margin: 0;
+}
+
+#jd-content #qv h2 {
+  font-size:1.05em;
+  font-weight:bold;
+  margin:12px 0 .25em 0;
+  padding:0 10px;
+  background-color:transparent;
+  color:#7BB026;
+  border:none;
+  left:0;
+  z-index:1;
+}
+
+/* END quickview sidebar element styles */
+
+/* Begin sidebox sidebar element styles */
+
+.sidebox-wrapper {
+  float:right;
+  clear:right;
+  width:310px; /* +35px padding */
+  background-color:#fff;
+  margin:0;
+  padding:0 0 20px 35px;
+}
+
+.sidebox {
+  border-left:1px solid #dee8f1;
+  background-color:#ffffee;
+  margin:0;
+  padding:8px 12px;
+  font-size:0.9em;
+  width:285px; /* +24px padding; +1px border */
+}
+
+.sidebox p {
+  margin-bottom: .75em;
+}
+
+.sidebox ul {
+  padding: 0 0 0 1.5em;
+}
+
+.sidebox li ul {
+  margin-top:0;
+  margin-bottom:.1em;
+}
+
+.sidebox li {
+padding:0 0 0 0em;
+}
+
+#jd-content .sidebox h2,
+#jd-content .sidebox h3,
+#jd-content .sidebox h4,
+#jd-content .sidebox h5 {
+  border:none;
+  font-size:1em;
+  margin:0;
+  padding:0 0 8px;
+  left:0;
+  z-index:0;
+}
+
+.sidebox hr {
+  background-color:#ccc;
+  border:none;
+}
+
+/* End sidebox sidebar element styles */
+
+/* BEGIN image and caption styles (originally for UI Guidelines docs) */
+
+table.image-caption {
+  padding:0;
+  margin:.5em 0;
+  border:0;
+}
+
+td.image-caption-i {
+  font-size:92%;
+  padding:0 5px;
+  margin:0;
+  border:0;
+}
+
+td.image-caption-i img {
+  padding:0 1em;
+  margin:0;
+}
+
+.image-list {
+  width:24px;
+  text-align:center;
+}
+
+td.image-caption-c {
+  font-size:92%;
+  padding:1em 2px 2px 2px;
+  margin:0;
+  border:0;
+  width:350px;
+}
+
+.grad-rule-top {
+background-image:url(images/grad-rule-qv.png);
+background-repeat:no-repeat;
+padding-top:1em;
+margin-top:0;
+}
+
+.image-caption-nested {
+  margin-top:0;
+  padding:0 0 0 1em;
+}
+
+.image-caption-nested td {
+  padding:0 4px 2px 0;
+  margin:0;
+  border:0;
+}
+
+/* END image and caption styles */
+
+/* table of contents */
+
+ol.toc {
+  margin: 0 0 1em 0;
+  padding: 0;
+  list-style: none;
+  font-size:95%;
+}
+
+ol.toc li {
+  font-weight: bold;
+  margin: 0 0 .5em 1em;
+  padding: 0;
+}
+
+ol.toc li p {
+  font-weight: normal;
+}
+
+ol.toc li ol {
+  margin: 0;
+  padding: 0;
+}
+
+ol.toc li li {
+  padding: 0;
+  margin: 0 0 0 1em;
+  font-weight: normal;
+  list-style: none;
+}
+
+table ol.toc {
+  margin-left: 0;
+}
+
+.columns td {
+  padding:0 5px;
+  border:none;
+}
+
+/* link table */
+.jd-linktable {
+  margin: 0 0 1em;
+  border-bottom: 1px solid #888;
+}
+.jd-linktable th,
+.jd-linktable td {
+  padding: 3px 5px;
+  vertical-align: top;
+  text-align: left;
+  border:none;
+}
+.jd-linktable tr {
+  background-color: #fff;
+}
+.jd-linktable td {
+  border-top: 1px solid #888;
+  background-color: inherit;
+}
+.jd-linktable td  p {
+  padding: 0 0 5px;
+}
+.jd-linktable .jd-linkcol {
+}
+.jd-linktable .jd-descrcol {
+}
+.jd-linktable .jd-typecol {
+  text-align:right;
+}
+.jd-linktable .jd-valcol {
+}
+.jd-linktable .jd-commentrow {
+  border-top:none;
+  padding-left:25px;
+}
+.jd-deprecated-warning {
+  margin-top: 0;
+  margin-bottom: 10px;
+}
+
+tr.alt-color {
+  background-color: #f6f6f6;
+}
+
+/* expando trigger */
+#jd-content .jd-expando-trigger-img {
+  margin:0;
+}
+
+/* jd-expando */
+.jd-inheritedlinks {
+  padding:0 0 0 13px
+}
+
+/* SDK PAGE */
+table.download tr {
+  background-color:#d9d9d9;
+}
+
+table.download tr.alt-color {
+  background-color:#ededed;
+}
+
+table.download td,
+table.download th {
+  border:2px solid #fff;
+  padding:10px 5px;
+}
+
+table.download th {
+  background-color:#6d8293;
+  color:#fff;
+}
+
+/* INLAY 180 COPY and 240PX EXTENSION */
+/* modified to 43px so that all browsers eliminate the package panel h-scroll */
+.g-tpl-240 .g-unit,
+.g-unit .g-tpl-240 .g-unit,
+.g-unit .g-unit .g-tpl-240 .g-unit {
+  display: block;
+  margin: 0 0 0 243px;
+  width: auto;
+  float: none;
+}
+.g-unit .g-unit .g-tpl-240 .g-first,
+.g-unit .g-tpl-240 .g-first,
+.g-tpl-240 .g-first {
+  display: block;
+  margin: 0;
+  width: 243px;
+  float: left;
+}
+/* 240px alt */
+.g-tpl-240-alt .g-unit,
+.g-unit .g-tpl-240-alt .g-unit,
+.g-unit .g-unit .g-tpl-240-alt .g-unit {
+  display: block;
+  margin: 0 243px 0 0;
+  width: auto;
+  float: none;
+}
+.g-unit .g-unit .g-tpl-240-alt .g-first,
+.g-unit .g-tpl-240-alt .g-first,
+.g-tpl-240-alt .g-first {
+  display: block;
+  margin: 0;
+  width: 243px;
+  float: right;
+}
+
+/* 200px */
+.g-tpl-200 .g-unit,
+.g-unit .g-tpl-200 .g-unit,
+.g-unit .g-unit .g-tpl-200 .g-unit {
+  display: block;
+  margin: 0 0 0 200px;
+  width: auto;
+  float: none;
+}
+.g-unit .g-unit .g-tpl-200 .g-first,
+.g-unit .g-tpl-200 .g-first,
+.g-tpl-200 .g-first {
+  display: block;
+  margin: 0;
+  width: 200px;
+  float: left;
+}
+/* 200px alt */
+.g-tpl-200-alt .g-unit,
+.g-unit .g-tpl-200-alt .g-unit,
+.g-unit .g-unit .g-tpl-200-alt .g-unit {
+  display: block;
+  margin: 0 200px 0 0;
+  width: auto;
+  float: none;
+}
+.g-unit .g-unit .g-tpl-200-alt .g-first,
+.g-unit .g-tpl-200-alt .g-first,
+.g-tpl-200-alt .g-first {
+  display: block;
+  margin: 0;
+  width: 200px;
+  float: right;
+}
+
+/* 190px */
+.g-tpl-190 .g-unit,
+.g-unit .g-tpl-190 .g-unit,
+.g-unit .g-unit .g-tpl-190 .g-unit {
+  display: block;
+  margin: 0 0 0 190px;
+  width: auto;
+  float: none;
+}
+.g-unit .g-unit .g-tpl-190 .g-first,
+.g-unit .g-tpl-190 .g-first,
+.g-tpl-190 .g-first {
+  display: block;
+  margin: 0;
+  width: 190px;
+  float: left;
+}
+/* 190px alt */
+.g-tpl-190-alt .g-unit,
+.g-unit .g-tpl-190-alt .g-unit,
+.g-unit .g-unit .g-tpl-190-alt .g-unit {
+  display: block;
+  margin: 0 190px 0 0;
+  width: auto;
+  float: none;
+}
+.g-unit .g-unit .g-tpl-190-alt .g-first,
+.g-unit .g-tpl-190-alt .g-first,
+.g-tpl-190-alt .g-first {
+  display: block;
+  margin: 0;
+  width: 190px;
+  float: right;
+}
+
+/* 180px */
+.g-tpl-180 .g-unit,
+.g-unit .g-tpl-180 .g-unit,
+.g-unit .g-unit .g-tpl-180 .g-unit {
+  display: block;
+  margin: 0 0 0 180px;
+  width: auto;
+  float: none;
+}
+.g-unit .g-unit .g-tpl-180 .g-first,
+.g-unit .g-tpl-180 .g-first,
+.g-tpl-180 .g-first {
+  display: block;
+  margin: 0;
+  width: 180px;
+  float: left;
+}
+/* 180px alt */
+.g-tpl-180-alt .g-unit,
+.g-unit .g-tpl-180-alt .g-unit,
+.g-unit .g-unit .g-tpl-180-alt .g-unit {
+  display: block;
+  margin: 0 180px 0 0;
+  width: auto;
+  float: none;
+}
+.g-unit .g-unit .g-tpl-180-alt .g-first,
+.g-unit .g-tpl-180-alt .g-first,
+.g-tpl-180-alt .g-first {
+  display: block;
+  margin: 0;
+  width: 180px;
+  float: right;
+}
+
+
+/* JQUERY RESIZABLE STYLES */
+.ui-resizable { position: relative; }
+.ui-resizable-handle { position: absolute; display: none; font-size: 0.1px; z-index:1; }
+.ui-resizable .ui-resizable-handle { display: block; }
+body .ui-resizable-disabled .ui-resizable-handle { display: none; }
+body .ui-resizable-autohide .ui-resizable-handle { display: none; }
+.ui-resizable-s { cursor: s-resize; height: 6px; width: 100%; bottom: 0px; left: 0px;
+  background: transparent url("images/resizable-s2.gif") repeat scroll center top; }
+.ui-resizable-e { cursor: e-resize; width: 6px; right: 0px; top: 0px; height: 100%;
+  background: transparent url("images/resizable-e2.gif") repeat scroll right center; }
+
+@media print {
+
+  body {
+    overflow:visible;
+  }
+
+  #header {
+    height:60px;
+  }
+
+  #headerLeft {
+    padding:0;
+  }
+
+  #header-tabs,
+  #headerRight,
+  #side-nav,
+  #api-info-block {
+    display:none;
+  }
+
+  #body-content {
+    position:inherit;
+  }
+
+  #doc-content {
+    margin-left:0 !important;
+    height:auto !important;
+    width:auto !important;
+    overflow:inherit;
+    display:inline;
+  }
+
+  #jd-header {
+    padding:10px 0;
+  }
+
+  #jd-content {
+    padding:15px 0 0;
+  }
+
+  #footer {
+    float:none;
+    margin:2em 0 0;
+  }
+
+  h4.jd-details-title {
+    border-bottom:1px solid #666;
+  }
+
+  pre {
+    /* these allow lines to break (if there's a white space) */
+    overflow: visible;
+    text-wrap: unrestricted;
+    white-space: -moz-pre-wrap; /* Moz */
+    white-space: -pre-wrap; /* Opera 4-6 */
+    white-space: -o-pre-wrap; /* Opera 7 */
+    white-space: pre-wrap; /* CSS3  */
+    word-wrap: break-word; /* IE 5.5+ */
+  }
+
+  h1, h2, h3, h4, h5, h6 {
+    page-break-after: avoid;
+  }
+
+  table, img {
+    page-break-inside: avoid;
+  }
+}
diff --git a/build/tools/droiddoc/templates/assets/android-developer-docs.js b/build/tools/droiddoc/templates/assets/android-developer-docs.js
new file mode 100644 (file)
index 0000000..5262bd8
--- /dev/null
@@ -0,0 +1,511 @@
+var resizePackagesNav;
+var classesNav;
+var devdocNav;
+var sidenav;
+var content;
+var HEADER_HEIGHT = 117;
+var cookie_namespace = 'android_developer';
+var NAV_PREF_TREE = "tree";
+var NAV_PREF_PANELS = "panels";
+var nav_pref;
+var toRoot;
+var isMobile = false; // true if mobile, so we can adjust some layout
+var isIE6 = false; // true if IE6
+
+// TODO: use $(document).ready instead
+function addLoadEvent(newfun) {
+  var current = window.onload;
+  if (typeof window.onload != 'function') {
+    window.onload = newfun;
+  } else {
+    window.onload = function() {
+      current();
+      newfun();
+    }
+  }
+}
+
+var agent = navigator['userAgent'].toLowerCase();
+// If a mobile phone, set flag and do mobile setup
+if ((agent.indexOf("mobile") != -1) ||      // android, iphone, ipod 
+    (agent.indexOf("blackberry") != -1) ||
+    (agent.indexOf("webos") != -1) ||
+    (agent.indexOf("mini") != -1)) {        // opera mini browsers 
+  isMobile = true;
+  addLoadEvent(mobileSetup);
+// If not a mobile browser, set the onresize event for IE6, and others
+} else if (agent.indexOf("msie 6") != -1) {
+  isIE6 = true;
+  addLoadEvent(function() {
+    window.onresize = resizeAll;
+  });
+} else {
+  addLoadEvent(function() {
+    window.onresize = resizeHeight;
+  });
+}
+
+function mobileSetup() {
+  $("body").css({'overflow':'auto'});
+  $("html").css({'overflow':'auto'});
+  $("#body-content").css({'position':'relative', 'top':'0'});
+  $("#doc-content").css({'overflow':'visible', 'border-left':'3px solid #DDD'});
+  $("#side-nav").css({'padding':'0'});
+  $("#nav-tree").css({'overflow-y': 'auto'});
+}
+
+/* loads the lists.js file to the page.
+Loading this in the head was slowing page load time */
+addLoadEvent( function() {
+  var lists = document.createElement("script");
+  lists.setAttribute("type","text/javascript");
+  lists.setAttribute("src", toRoot+"reference/lists.js");
+  document.getElementsByTagName("head")[0].appendChild(lists);
+} );
+
+addLoadEvent( function() {
+  $("pre:not(.no-pretty-print)").addClass("prettyprint");
+  prettyPrint();
+} );
+
+function setToRoot(root) {
+  toRoot = root;
+  // note: toRoot also used by carousel.js
+}
+
+function restoreWidth(navWidth) {
+  var windowWidth = $(window).width() + "px";
+  content.css({marginLeft:parseInt(navWidth) + 6 + "px"}); //account for 6px-wide handle-bar
+
+  if (isIE6) {
+    content.css({width:parseInt(windowWidth) - parseInt(navWidth) - 6 + "px"}); // necessary in order for scrollbars to be visible
+  }
+
+  sidenav.css({width:navWidth});
+  resizePackagesNav.css({width:navWidth});
+  classesNav.css({width:navWidth});
+  $("#packages-nav").css({width:navWidth});
+}
+
+function restoreHeight(packageHeight) {
+  var windowHeight = ($(window).height() - HEADER_HEIGHT);
+  var swapperHeight = windowHeight - 13;
+  $("#swapper").css({height:swapperHeight + "px"});
+  sidenav.css({height:windowHeight + "px"});
+  content.css({height:windowHeight + "px"});
+  resizePackagesNav.css({maxHeight:swapperHeight + "px", height:packageHeight});
+  classesNav.css({height:swapperHeight - parseInt(packageHeight) + "px"});
+  $("#packages-nav").css({height:parseInt(packageHeight) - 6 + "px"}); //move 6px to give space for the resize handle
+  devdocNav.css({height:sidenav.css("height")});
+  $("#nav-tree").css({height:swapperHeight + "px"});
+}
+
+function readCookie(cookie) {
+  var myCookie = cookie_namespace+"_"+cookie+"=";
+  if (document.cookie) {
+    var index = document.cookie.indexOf(myCookie);
+    if (index != -1) {
+      var valStart = index + myCookie.length;
+      var valEnd = document.cookie.indexOf(";", valStart);
+      if (valEnd == -1) {
+        valEnd = document.cookie.length;
+      }
+      var val = document.cookie.substring(valStart, valEnd);
+      return val;
+    }
+  }
+  return 0;
+}
+
+function writeCookie(cookie, val, section, expiration) {
+  if (val==undefined) return;
+  section = section == null ? "_" : "_"+section+"_";
+  if (expiration == null) {
+    var date = new Date();
+    date.setTime(date.getTime()+(10*365*24*60*60*1000)); // default expiration is one week
+    expiration = date.toGMTString();
+  }
+  document.cookie = cookie_namespace + section + cookie + "=" + val + "; expires=" + expiration+"; path=/";
+} 
+
+function init() {
+  $("#side-nav").css({position:"absolute",left:0});
+  content = $("#doc-content");
+  resizePackagesNav = $("#resize-packages-nav");
+  classesNav = $("#classes-nav");
+  sidenav = $("#side-nav");
+  devdocNav = $("#devdoc-nav");
+
+  var cookiePath = "";
+  if (location.href.indexOf("/reference/") != -1) {
+    cookiePath = "reference_";
+  } else if (location.href.indexOf("/guide/") != -1) {
+    cookiePath = "guide_";
+  } else if (location.href.indexOf("/sdk/") != -1) {
+    cookiePath = "sdk_";
+  } else if (location.href.indexOf("/resources/") != -1) {
+    cookiePath = "resources_";
+  }
+
+  if (!isMobile) {
+    $("#resize-packages-nav").resizable({handles: "s", resize: function(e, ui) { resizePackagesHeight(); } });
+    $("#side-nav").resizable({handles: "e", resize: function(e, ui) { resizeWidth(); } });
+    var cookieWidth = readCookie(cookiePath+'width');
+    var cookieHeight = readCookie(cookiePath+'height');
+    if (cookieWidth) {
+      restoreWidth(cookieWidth);
+    } else if ($("#side-nav").length) {
+      resizeWidth();
+    }
+    if (cookieHeight) {
+      restoreHeight(cookieHeight);
+    } else {
+      resizeHeight();
+    }
+  }
+
+  if (devdocNav.length) { // only dev guide and sdk 
+    highlightNav(location.href); 
+  }
+}
+
+function highlightNav(fullPageName) {
+  var lastSlashPos = fullPageName.lastIndexOf("/");
+  var firstSlashPos;
+  if (fullPageName.indexOf("/guide/") != -1) {
+    firstSlashPos = fullPageName.indexOf("/guide/");
+  } else if (fullPageName.indexOf("/sdk/") != -1) {
+    firstSlashPos = fullPageName.indexOf("/sdk/");
+  } else if (fullPageName.indexOf("/resources/") != -1) {
+    firstSlashPos = fullPageName.indexOf("/resources/");
+  }
+  if (lastSlashPos == (fullPageName.length - 1)) { // if the url ends in slash (add 'index.html')
+    fullPageName = fullPageName + "index.html";
+  }
+  var htmlPos = fullPageName.lastIndexOf(".html", fullPageName.length);
+  var pathPageName = fullPageName.slice(firstSlashPos, htmlPos + 5);
+  var link = $("#devdoc-nav a[href$='"+ pathPageName+"']");
+  if ((link.length == 0) && ((fullPageName.indexOf("/guide/") != -1) || (fullPageName.indexOf("/resources/") != -1))) { 
+// if there's no match, then let's backstep through the directory until we find an index.html page that matches our ancestor directories (only for dev guide and resources)
+    lastBackstep = pathPageName.lastIndexOf("/");
+    while (link.length == 0) {
+      backstepDirectory = pathPageName.lastIndexOf("/", lastBackstep);
+      link = $("#devdoc-nav a[href$='"+ pathPageName.slice(0, backstepDirectory + 1)+"index.html']");
+      lastBackstep = pathPageName.lastIndexOf("/", lastBackstep - 1);
+      if (lastBackstep == 0) break;
+    }
+  }
+
+  // add 'selected' to the <li> or <div> that wraps this <a>
+  link.parent().addClass('selected');
+
+  // if we're in a toggleable root link (<li class=toggle-list><div><a>)
+  if (link.parent().parent().hasClass('toggle-list')) {
+    toggle(link.parent().parent(), false); // open our own list
+    // then also check if we're in a third-level nested list that's toggleable
+    if (link.parent().parent().parent().is(':hidden')) {
+      toggle(link.parent().parent().parent().parent(), false); // open the super parent list
+    }
+  }
+  // if we're in a normal nav link (<li><a>) and the parent <ul> is hidden
+  else if (link.parent().parent().is(':hidden')) {
+    toggle(link.parent().parent().parent(), false); // open the parent list
+    // then also check if the parent list is also nested in a hidden list
+    if (link.parent().parent().parent().parent().is(':hidden')) {
+      toggle(link.parent().parent().parent().parent().parent(), false); // open the super parent list
+    }
+  }
+}
+
+/* Resize the height of the nav panels in the reference,
+ * and save the new size to a cookie */
+function resizePackagesHeight() {
+  var windowHeight = ($(window).height() - HEADER_HEIGHT);
+  var swapperHeight = windowHeight - 13; // move 13px for swapper link at the bottom
+  resizePackagesNav.css({maxHeight:swapperHeight + "px"});
+  classesNav.css({height:swapperHeight - parseInt(resizePackagesNav.css("height")) + "px"});
+
+  $("#swapper").css({height:swapperHeight + "px"});
+  $("#packages-nav").css({height:parseInt(resizePackagesNav.css("height")) - 6 + "px"}); //move 6px for handle
+
+  var basePath = getBaseUri(location.pathname);
+  var section = basePath.substring(1,basePath.indexOf("/",1));
+  writeCookie("height", resizePackagesNav.css("height"), section, null);
+}
+
+/* Resize the height of the side-nav and doc-content divs,
+ * which creates the frame effect */
+function resizeHeight() {
+  var docContent = $("#doc-content");
+
+  // Get the window height and always resize the doc-content and side-nav divs
+  var windowHeight = ($(window).height() - HEADER_HEIGHT);
+  docContent.css({height:windowHeight + "px"});
+  $("#side-nav").css({height:windowHeight + "px"});
+
+  var href = location.href;
+  // If in the reference docs, also resize the "swapper", "classes-nav", and "nav-tree"  divs
+  if (href.indexOf("/reference/") != -1) {
+    var swapperHeight = windowHeight - 13;
+    $("#swapper").css({height:swapperHeight + "px"});
+    $("#classes-nav").css({height:swapperHeight - parseInt(resizePackagesNav.css("height")) + "px"});
+    $("#nav-tree").css({height:swapperHeight + "px"});
+
+  // Also resize the "devdoc-nav" div
+  } else if ($("#devdoc-nav").length) {
+    $("#devdoc-nav").css({height:sidenav.css("height")});
+  }
+
+  // Hide the "Go to top" link if there's no vertical scroll
+  if ( parseInt($("#jd-content").css("height")) <= parseInt(docContent.css("height")) ) {
+    $("a[href='#top']").css({'display':'none'});
+  } else {
+    $("a[href='#top']").css({'display':'inline'});
+  }
+}
+
+/* Resize the width of the "side-nav" and the left margin of the "doc-content" div,
+ * which creates the resizable side bar */
+function resizeWidth() {
+  var windowWidth = $(window).width() + "px";
+  var sidenav = $("#side-nav");
+  if (sidenav.length) {
+    var sidenavWidth = sidenav.css("width");
+  } else {
+    var sidenavWidth = 0;
+  }
+  content.css({marginLeft:parseInt(sidenavWidth) + 6 + "px"}); //account for 6px-wide handle-bar
+
+  if (isIE6) {
+    content.css({width:parseInt(windowWidth) - parseInt(sidenavWidth) - 6 + "px"}); // necessary in order to for scrollbars to be visible
+  }
+
+  resizePackagesNav.css({width:sidenavWidth});
+  classesNav.css({width:sidenavWidth});
+  $("#packages-nav").css({width:sidenavWidth});
+
+  if (sidenav.length) { // Must check if the nav exists because IE6 calls resizeWidth() from resizeAll() for all pages
+    var basePath = getBaseUri(location.pathname);
+    var section = basePath.substring(1,basePath.indexOf("/",1));
+    writeCookie("width", sidenavWidth, section, null);
+  }
+}
+
+/* For IE6 only,
+ * because it can't properly perform auto width for "doc-content" div,
+ * avoiding this for all browsers provides better performance */
+function resizeAll() {
+  resizeHeight();
+  resizeWidth();
+}
+
+function getBaseUri(uri) {
+  var intlUrl = (uri.substring(0,6) == "/intl/");
+  if (intlUrl) {
+    base = uri.substring(uri.indexOf('intl/')+5,uri.length);
+    base = base.substring(base.indexOf('/')+1, base.length);
+      //alert("intl, returning base url: /" + base);
+    return ("/" + base);
+  } else {
+      //alert("not intl, returning uri as found.");
+    return uri;
+  }
+}
+
+function requestAppendHL(uri) {
+//append "?hl=<lang> to an outgoing request (such as to blog)
+  var lang = getLangPref();
+  if (lang) {
+    var q = 'hl=' + lang;
+    uri += '?' + q;
+    window.location = uri;
+    return false;
+  } else {
+    return true;
+  }
+}
+
+function loadLast(cookiePath) {
+  var location = window.location.href;
+  if (location.indexOf("/"+cookiePath+"/") != -1) {
+    return true;
+  }
+  var lastPage = readCookie(cookiePath + "_lastpage");
+  if (lastPage) {
+    window.location = lastPage;
+    return false;
+  }
+  return true;
+}
+
+$(window).unload(function(){
+  var path = getBaseUri(location.pathname);
+  if (path.indexOf("/reference/") != -1) {
+    writeCookie("lastpage", path, "reference", null);
+  } else if (path.indexOf("/guide/") != -1) {
+    writeCookie("lastpage", path, "guide", null);
+  } else if (path.indexOf("/resources/") != -1) {
+    writeCookie("lastpage", path, "resources", null);
+  }
+});
+
+function toggle(obj, slide) {
+  var ul = $("ul:first", obj);
+  var li = ul.parent();
+  if (li.hasClass("closed")) {
+    if (slide) {
+      ul.slideDown("fast");
+    } else {
+      ul.show();
+    }
+    li.removeClass("closed");
+    li.addClass("open");
+    $(".toggle-img", li).attr("title", "hide pages");
+  } else {
+    ul.slideUp("fast");
+    li.removeClass("open");
+    li.addClass("closed");
+    $(".toggle-img", li).attr("title", "show pages");
+  }
+}
+
+function buildToggleLists() {
+  $(".toggle-list").each(
+    function(i) {
+      $("div:first", this).append("<a class='toggle-img' href='#' title='show pages' onClick='toggle(this.parentNode.parentNode, true); return false;'></a>");
+      $(this).addClass("closed");
+    });
+}
+
+function getNavPref() {
+  var v = readCookie('reference_nav');
+  if (v != NAV_PREF_TREE) {
+    v = NAV_PREF_PANELS;
+  }
+  return v;
+}
+
+function chooseDefaultNav() {
+  nav_pref = getNavPref();
+  if (nav_pref == NAV_PREF_TREE) {
+    $("#nav-panels").toggle();
+    $("#panel-link").toggle();
+    $("#nav-tree").toggle();
+    $("#tree-link").toggle();
+  }
+}
+
+function swapNav() {
+  if (nav_pref == NAV_PREF_TREE) {
+    nav_pref = NAV_PREF_PANELS;
+  } else {
+    nav_pref = NAV_PREF_TREE;
+    init_default_navtree(toRoot);
+  }
+  var date = new Date();
+  date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years
+  writeCookie("nav", nav_pref, "reference", date.toGMTString());
+
+  $("#nav-panels").toggle();
+  $("#panel-link").toggle();
+  $("#nav-tree").toggle();
+  $("#tree-link").toggle();
+
+  if ($("#nav-tree").is(':visible')) scrollIntoView("nav-tree");
+  else {
+    scrollIntoView("packages-nav");
+    scrollIntoView("classes-nav");
+  }
+}
+
+function scrollIntoView(nav) {
+  var navObj = $("#"+nav);
+  if (navObj.is(':visible')) {
+    var selected = $(".selected", navObj);
+    if (selected.length == 0) return;
+    if (selected.is("div")) selected = selected.parent();
+
+    var scrolling = document.getElementById(nav);
+    var navHeight = navObj.height();
+    var offsetTop = selected.position().top;
+    if (selected.parent().parent().is(".toggle-list")) offsetTop += selected.parent().parent().position().top;
+    if(offsetTop > navHeight - 92) {
+      scrolling.scrollTop = offsetTop - navHeight + 92;
+    }
+  }
+}
+
+function changeTabLang(lang) {
+  var nodes = $("#header-tabs").find("."+lang);
+  for (i=0; i < nodes.length; i++) { // for each node in this language 
+    var node = $(nodes[i]);
+    node.siblings().css("display","none"); // hide all siblings 
+    if (node.not(":empty").length != 0) { //if this languages node has a translation, show it 
+      node.css("display","inline");
+    } else { //otherwise, show English instead 
+      node.css("display","none");
+      node.siblings().filter(".en").css("display","inline");
+    }
+  }
+}
+
+function changeNavLang(lang) {
+  var nodes = $("#side-nav").find("."+lang);
+  for (i=0; i < nodes.length; i++) { // for each node in this language 
+    var node = $(nodes[i]);
+    node.siblings().css("display","none"); // hide all siblings 
+    if (node.not(":empty").length != 0) { // if this languages node has a translation, show it 
+      node.css("display","inline");
+    } else { // otherwise, show English instead 
+      node.css("display","none");
+      node.siblings().filter(".en").css("display","inline");
+    }
+  }
+}
+
+function changeDocLang(lang) {
+  changeTabLang(lang);
+  changeNavLang(lang);
+}
+
+function changeLangPref(lang, refresh) {
+  var date = new Date();
+  expires = date.toGMTString(date.setTime(date.getTime()+(10*365*24*60*60*1000))); // keep this for 50 years
+  //alert("expires: " + expires)
+  writeCookie("pref_lang", lang, null, expires);
+  //changeDocLang(lang);
+  if (refresh) {
+    l = getBaseUri(location.pathname);
+    window.location = l;
+  }
+}
+
+function loadLangPref() {
+  var lang = readCookie("pref_lang");
+  if (lang != 0) {
+    $("#language").find("option[value='"+lang+"']").attr("selected",true);
+  }
+}
+
+function getLangPref() {
+  var lang = $("#language").find(":selected").attr("value");
+  if (!lang) {
+    lang = readCookie("pref_lang");
+  }
+  return (lang != 0) ? lang : 'en';
+}
+
+
+function toggleContent(obj) {
+  var button = $(obj);
+  var div = $(obj.parentNode);
+  var toggleMe = $(".toggle-content-toggleme",div);
+  if (button.hasClass("show")) {
+    toggleMe.slideDown();
+    button.removeClass("show").addClass("hide");
+  } else {
+    toggleMe.slideUp();
+    button.removeClass("hide").addClass("show");
+  }
+  $("span", button).toggle();
+}
diff --git a/build/tools/droiddoc/templates/assets/android-developer-reference.js b/build/tools/droiddoc/templates/assets/android-developer-reference.js
new file mode 100644 (file)
index 0000000..daddde0
--- /dev/null
@@ -0,0 +1,390 @@
+
+/* API LEVEL TOGGLE */
+addLoadEvent(changeApiLevel);
+
+var API_LEVEL_ENABLED_COOKIE = "api_level_enabled";
+var API_LEVEL_COOKIE = "api_level";
+var minLevel = 1;
+
+function toggleApiLevelSelector(checkbox) {
+  var date = new Date();
+  date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years
+  var expiration = date.toGMTString();
+  if (checkbox.checked) {
+    $("#apiLevelSelector").removeAttr("disabled");
+    $("#api-level-toggle label").removeClass("disabled");
+    writeCookie(API_LEVEL_ENABLED_COOKIE, 1, null, expiration);
+  } else {
+    $("#apiLevelSelector").attr("disabled","disabled");
+    $("#api-level-toggle label").addClass("disabled");
+    writeCookie(API_LEVEL_ENABLED_COOKIE, 0, null, expiration);
+  }
+  changeApiLevel();
+}
+
+function buildApiLevelSelector() {
+  var maxLevel = SINCE_DATA.length;
+  var userApiLevelEnabled = readCookie(API_LEVEL_ENABLED_COOKIE);
+  var userApiLevel = readCookie(API_LEVEL_COOKIE);
+  userApiLevel = userApiLevel == 0 ? maxLevel : userApiLevel; // If there's no cookie (zero), use the max by default
+
+  if (userApiLevelEnabled == 0) {
+    $("#apiLevelSelector").attr("disabled","disabled");
+  } else {
+    $("#apiLevelCheckbox").attr("checked","checked");
+    $("#api-level-toggle label").removeClass("disabled");
+  }
+  
+  minLevel = $("body").attr("class");
+  var select = $("#apiLevelSelector").html("").change(changeApiLevel);
+  for (var i = maxLevel-1; i >= 0; i--) {
+    var option = $("<option />").attr("value",""+SINCE_DATA[i]).append(""+SINCE_DATA[i]);
+  //  if (SINCE_DATA[i] < minLevel) option.addClass("absent"); // always false for strings (codenames)
+    select.append(option);
+  }
+  
+  // get the DOM element and use setAttribute cuz IE6 fails when using jquery .attr('selected',true)
+  var selectedLevelItem = $("#apiLevelSelector option[value='"+userApiLevel+"']").get(0);
+  selectedLevelItem.setAttribute('selected',true);
+}
+
+function changeApiLevel() {
+  var maxLevel = SINCE_DATA.length;
+  var userApiLevelEnabled = readCookie(API_LEVEL_ENABLED_COOKIE);
+  var selectedLevel = maxLevel;
+  
+  if (userApiLevelEnabled == 0) {
+    toggleVisisbleApis(selectedLevel, "body");
+  } else {
+    selectedLevel = $("#apiLevelSelector option:selected").val();
+    toggleVisisbleApis(selectedLevel, "body");
+    
+    var date = new Date();
+    date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years
+    var expiration = date.toGMTString();
+    writeCookie(API_LEVEL_COOKIE, selectedLevel, null, expiration);
+  }
+  
+  if (selectedLevel < minLevel) {
+    var thing = ($("#jd-header").html().indexOf("package") != -1) ? "package" : "class";
+    $("#naMessage").show().html("<div><p><strong>This " + thing + " is not available with API Level " + selectedLevel + ".</strong></p>"
+                              + "<p>To use this " + thing + ", your application must specify API Level " + minLevel + " or higher in its manifest "
+                              + "and be compiled against a version of the Android library that supports an equal or higher API Level. To reveal this "
+                              + "document, change the value of the API Level filter above.</p>"
+                              + "<p><a href='" +toRoot+ "guide/appendix/api-levels.html'>What is the API Level?</a></p></div>");
+  } else {
+    $("#naMessage").hide();
+  }
+}
+
+function toggleVisisbleApis(selectedLevel, context) {
+  var apis = $(".api",context);
+  apis.each(function(i) {
+    var obj = $(this);
+    var className = obj.attr("class");
+    var apiLevelIndex = className.lastIndexOf("-")+1;
+    var apiLevelEndIndex = className.indexOf(" ", apiLevelIndex);
+    apiLevelEndIndex = apiLevelEndIndex != -1 ? apiLevelEndIndex : className.length;
+    var apiLevel = className.substring(apiLevelIndex, apiLevelEndIndex);
+    if (apiLevel > selectedLevel) obj.addClass("absent").attr("title","Requires API Level "+apiLevel+" or higher");
+    else obj.removeClass("absent").removeAttr("title");
+  });
+}
+
+/* NAVTREE */
+
+function new_node(me, mom, text, link, children_data, api_level)
+{
+  var node = new Object();
+  node.children = Array();
+  node.children_data = children_data;
+  node.depth = mom.depth + 1;
+
+  node.li = document.createElement("li");
+  mom.get_children_ul().appendChild(node.li);
+
+  node.label_div = document.createElement("div");
+  node.label_div.className = "label";
+  if (api_level != null) {
+    $(node.label_div).addClass("api");
+    $(node.label_div).addClass("api-level-"+api_level);
+  }
+  node.li.appendChild(node.label_div);
+  node.label_div.style.paddingLeft = 10*node.depth + "px";
+
+  if (children_data == null) {
+    // 12 is the width of the triangle and padding extra space
+    node.label_div.style.paddingLeft = ((10*node.depth)+12) + "px";
+  } else {
+    node.label_div.style.paddingLeft = 10*node.depth + "px";
+    node.expand_toggle = document.createElement("a");
+    node.expand_toggle.href = "javascript:void(0)";
+    node.expand_toggle.onclick = function() {
+          if (node.expanded) {
+            $(node.get_children_ul()).slideUp("fast");
+            node.plus_img.src = me.toroot + "assets/images/triangle-closed-small.png";
+            node.expanded = false;
+          } else {
+            expand_node(me, node);
+          }
+       };
+    node.label_div.appendChild(node.expand_toggle);
+
+    node.plus_img = document.createElement("img");
+    node.plus_img.src = me.toroot + "assets/images/triangle-closed-small.png";
+    node.plus_img.className = "plus";
+    node.plus_img.border = "0";
+    node.expand_toggle.appendChild(node.plus_img);
+
+    node.expanded = false;
+  }
+
+  var a = document.createElement("a");
+  node.label_div.appendChild(a);
+  node.label = document.createTextNode(text);
+  a.appendChild(node.label);
+  if (link) {
+    a.href = me.toroot + link;
+  } else {
+    if (children_data != null) {
+      a.className = "nolink";
+      a.href = "javascript:void(0)";
+      a.onclick = node.expand_toggle.onclick;
+      // This next line shouldn't be necessary.  I'll buy a beer for the first
+      // person who figures out how to remove this line and have the link
+      // toggle shut on the first try. --joeo@android.com
+      node.expanded = false;
+    }
+  }
+  
+
+  node.children_ul = null;
+  node.get_children_ul = function() {
+      if (!node.children_ul) {
+        node.children_ul = document.createElement("ul");
+        node.children_ul.className = "children_ul";
+        node.children_ul.style.display = "none";
+        node.li.appendChild(node.children_ul);
+      }
+      return node.children_ul;
+    };
+
+  return node;
+}
+
+function expand_node(me, node)
+{
+  if (node.children_data && !node.expanded) {
+    if (node.children_visited) {
+      $(node.get_children_ul()).slideDown("fast");
+    } else {
+      get_node(me, node);
+      if ($(node.label_div).hasClass("absent")) $(node.get_children_ul()).addClass("absent");
+      $(node.get_children_ul()).slideDown("fast");
+    }
+    node.plus_img.src = me.toroot + "assets/images/triangle-opened-small.png";
+    node.expanded = true;
+    
+    // perform api level toggling because new nodes are new to the DOM
+    var selectedLevel = $("#apiLevelSelector option:selected").val();
+    toggleVisisbleApis(selectedLevel, "#side-nav");
+  }
+}
+
+function get_node(me, mom)
+{
+  mom.children_visited = true;
+  for (var i in mom.children_data) {
+    var node_data = mom.children_data[i];
+    mom.children[i] = new_node(me, mom, node_data[0], node_data[1],
+        node_data[2], node_data[3]);
+  }
+}
+
+function this_page_relative(toroot)
+{
+  var full = document.location.pathname;
+  var file = "";
+  if (toroot.substr(0, 1) == "/") {
+    if (full.substr(0, toroot.length) == toroot) {
+      return full.substr(toroot.length);
+    } else {
+      // the file isn't under toroot.  Fail.
+      return null;
+    }
+  } else {
+    if (toroot != "./") {
+      toroot = "./" + toroot;
+    }
+    do {
+      if (toroot.substr(toroot.length-3, 3) == "../" || toroot == "./") {
+        var pos = full.lastIndexOf("/");
+        file = full.substr(pos) + file;
+        full = full.substr(0, pos);
+        toroot = toroot.substr(0, toroot.length-3);
+      }
+    } while (toroot != "" && toroot != "/");
+    return file.substr(1);
+  }
+}
+
+function find_page(url, data)
+{
+  var nodes = data;
+  var result = null;
+  for (var i in nodes) {
+    var d = nodes[i];
+    if (d[1] == url) {
+      return new Array(i);
+    }
+    else if (d[2] != null) {
+      result = find_page(url, d[2]);
+      if (result != null) {
+        return (new Array(i).concat(result));
+      }
+    }
+  }
+  return null;
+}
+
+function load_navtree_data(toroot) {
+  var navtreeData = document.createElement("script");
+  navtreeData.setAttribute("type","text/javascript");
+  navtreeData.setAttribute("src", toroot+"navtree_data.js");
+  $("head").append($(navtreeData));
+}
+
+function init_default_navtree(toroot) {
+  init_navtree("nav-tree", toroot, NAVTREE_DATA);
+  
+  // perform api level toggling because because the whole tree is new to the DOM
+  var selectedLevel = $("#apiLevelSelector option:selected").val();
+  toggleVisisbleApis(selectedLevel, "#side-nav");
+}
+
+function init_navtree(navtree_id, toroot, root_nodes)
+{
+  var me = new Object();
+  me.toroot = toroot;
+  me.node = new Object();
+
+  me.node.li = document.getElementById(navtree_id);
+  me.node.children_data = root_nodes;
+  me.node.children = new Array();
+  me.node.children_ul = document.createElement("ul");
+  me.node.get_children_ul = function() { return me.node.children_ul; };
+  //me.node.children_ul.className = "children_ul";
+  me.node.li.appendChild(me.node.children_ul);
+  me.node.depth = 0;
+
+  get_node(me, me.node);
+
+  me.this_page = this_page_relative(toroot);
+  me.breadcrumbs = find_page(me.this_page, root_nodes);
+  if (me.breadcrumbs != null && me.breadcrumbs.length != 0) {
+    var mom = me.node;
+    for (var i in me.breadcrumbs) {
+      var j = me.breadcrumbs[i];
+      mom = mom.children[j];
+      expand_node(me, mom);
+    }
+    mom.label_div.className = mom.label_div.className + " selected";
+    addLoadEvent(function() {
+      scrollIntoView("nav-tree");
+      });
+  }
+}
+
+/* TOGGLE INHERITED MEMBERS */
+
+/* Toggle an inherited class (arrow toggle)
+ * @param linkObj  The link that was clicked.
+ * @param expand  'true' to ensure it's expanded. 'false' to ensure it's closed.
+ *                'null' to simply toggle.
+ */
+function toggleInherited(linkObj, expand) {
+    var base = linkObj.getAttribute("id");
+    var list = document.getElementById(base + "-list");
+    var summary = document.getElementById(base + "-summary");
+    var trigger = document.getElementById(base + "-trigger");
+    var a = $(linkObj);
+    if ( (expand == null && a.hasClass("closed")) || expand ) {
+        list.style.display = "none";
+        summary.style.display = "block";
+        trigger.src = toRoot + "assets/images/triangle-opened.png";
+        a.removeClass("closed");
+        a.addClass("opened");
+    } else if ( (expand == null && a.hasClass("opened")) || (expand == false) ) {
+        list.style.display = "block";
+        summary.style.display = "none";
+        trigger.src = toRoot + "assets/images/triangle-closed.png";
+        a.removeClass("opened");
+        a.addClass("closed");
+    }
+    return false;
+}
+
+/* Toggle all inherited classes in a single table (e.g. all inherited methods)
+ * @param linkObj  The link that was clicked.
+ * @param expand  'true' to ensure it's expanded. 'false' to ensure it's closed.
+ *                'null' to simply toggle.
+ */
+function toggleAllInherited(linkObj, expand) {
+  var a = $(linkObj);
+  var table = $(a.parent().parent().parent()); // ugly way to get table/tbody
+  var expandos = $(".jd-expando-trigger", table);
+  if ( (expand == null && a.text() == "[Expand]") || expand ) {
+    expandos.each(function(i) {
+      toggleInherited(this, true);
+    });
+    a.text("[Collapse]");
+  } else if ( (expand == null && a.text() == "[Collapse]") || (expand == false) ) {
+    expandos.each(function(i) {
+      toggleInherited(this, false);
+    });
+    a.text("[Expand]");
+  }
+  return false;
+}
+
+/* Toggle all inherited members in the class (link in the class title)
+ */
+function toggleAllClassInherited() {
+  var a = $("#toggleAllClassInherited"); // get toggle link from class title
+  var toggles = $(".toggle-all", $("#doc-content"));
+  if (a.text() == "[Expand All]") {
+    toggles.each(function(i) {
+      toggleAllInherited(this, true);
+    });
+    a.text("[Collapse All]");
+  } else {
+    toggles.each(function(i) {
+      toggleAllInherited(this, false);
+    });
+    a.text("[Expand All]");
+  }
+  return false;
+}
+
+/* Expand all inherited members in the class. Used when initiating page search */
+function ensureAllInheritedExpanded() {
+  var toggles = $(".toggle-all", $("#doc-content"));
+  toggles.each(function(i) {
+    toggleAllInherited(this, true);
+  });
+  $("#toggleAllClassInherited").text("[Collapse All]");
+}
+
+
+/* HANDLE KEY EVENTS
+ * - Listen for Ctrl+F (Cmd on Mac) and expand all inherited members (to aid page search)
+ */
+var agent = navigator['userAgent'].toLowerCase();
+var mac = agent.indexOf("macintosh") != -1;
+
+$(document).keydown( function(e) {
+var control = mac ? e.metaKey && !e.ctrlKey : e.ctrlKey; // get ctrl key
+  if (control && e.which == 70) {  // 70 is "F"
+    ensureAllInheritedExpanded();
+  }
+});
\ No newline at end of file
diff --git a/build/tools/droiddoc/templates/assets/carousel.js b/build/tools/droiddoc/templates/assets/carousel.js
new file mode 100644 (file)
index 0000000..9512f8f
--- /dev/null
@@ -0,0 +1,311 @@
+/* file: carousel.js
+   date: oct 2008
+   author: jeremydw,smain
+   info: operates the carousel widget for announcements on 
+         the android developers home page. modified from the
+         original market.js from jeremydw. */
+
+/* -- video switcher -- */
+
+var oldVid = "multi"; // set the default video
+var nowPlayingString = "Now playing:";
+var assetsRoot = "assets/";
+
+
+/* -- app thumbnail switcher -- */
+
+var currentDroid;
+var oldDroid;
+
+// shows a random application
+function randomDroid(){
+
+       // count the total number of apps
+       var droidListLength = 0;
+       for (var k in droidList)
+               droidListLength++;
+               
+       // pick a random app and show it
+  var j = 0;
+  var i = Math.floor(droidListLength*Math.random());
+  for (var x in droidList) {
+    if(j++ == i){
+       currentDroid = x;
+       showPreview(x);
+       centerSlide(x);
+    }
+  }
+
+}
+
+// shows a bulletin, swaps the carousel highlighting
+function droid(appName){
+
+  oldDroid = $("#droidlink-"+currentDroid);
+  currentDroid = appName;
+
+  var droid = droidList[appName];
+  
+  $("#"+appName).show().siblings().hide();
+
+  if(oldDroid)
+    oldDroid.removeClass("selected");
+
+  $("#droidlink-"+appName).addClass("selected");
+}
+
+
+// -- * build the carousel based on the droidList * -- //
+function buildCarousel() {
+  var appList = document.getElementById("app-list");
+  for (var x in droidList) {
+    var droid = droidList[x];
+    var icon = droid.icon;
+    var name = droid.name;
+    var a = document.createElement("a");
+    var img = document.createElement("img");
+    var br = document.createElement("br");
+    var span = document.createElement("span");
+    var text = document.createTextNode(droid.name);
+
+    a.setAttribute("id", "droidlink-" + x);
+    a.className = x;
+    a.setAttribute("href", "#");
+    a.onclick = function() { showPreview(this.className); return false; }
+    img.setAttribute("src", toRoot + assetsRoot + "images/home/" + droid.icon);
+    img.setAttribute("alt", "");
+
+    span.appendChild(text);
+    a.appendChild(img);
+    a.appendChild(br);
+    a.appendChild(span);
+    appList.appendChild(a);
+    
+    
+    /* add the bulletins */
+    var layout = droid.layout;
+    var div = document.createElement("div");
+    var imgDiv = document.createElement("div");
+    var descDiv = document.createElement("div");
+    
+    div.setAttribute("id", x);
+    div.setAttribute("style", "display:none");
+    imgDiv.setAttribute("class", "bulletinImg");
+    descDiv.setAttribute("class", "bulletinDesc");
+       
+         if (layout == "imgLeft") {
+           $(imgDiv).addClass("img-left");
+           $(descDiv).addClass("desc-right");
+         } else if (layout == "imgTop") {
+           $(imgDiv).addClass("img-top");
+           $(descDiv).addClass("desc-bottom");
+         } else if (layout == "imgRight") {
+           $(imgDiv).addClass("img-right");
+           $(descDiv).addClass("desc-left");
+         }
+       
+         imgDiv.innerHTML = "<img src='" + toRoot + assetsRoot + "images/home/" + droid.img + "'>";
+         descDiv.innerHTML = (droid.title != "") ? "<h3>" + droid.title + "</h3>" + droid.desc : droid.desc;
+               $(div).append(imgDiv);
+               $(div).append(descDiv);
+    
+    $("#carouselMain").append(div);
+    
+  }
+}
+
+// -- * slider * -- //
+
+// -- dependencies:
+//    (1) div containing slides, (2) a "clip" div to hide the scroller
+//    (3) control arrows
+
+// -- * config below * -- //
+
+var slideCode = droidList; // the dictionary of slides
+var slideList = 'app-list'; // the div containing the slides
+var arrowRight = 'arrow-right'; // the right control arrow
+var arrowLeft = 'arrow-left'; // the left control arrow
+
+
+function showPreview(slideName) {
+  centerSlide(slideName);
+  if (slideName.indexOf('selected') != -1) {
+    return false;
+  }
+  droid(slideName); // do this function when slide is clicked
+}
+
+var thumblist = document.getElementById(slideList);// the div containing the slides
+
+var slideWidth = 144; // width of a slide including all margins, etc.
+var slidesAtOnce = 3; // no. of slides to appear at once (requires odd number to have a centered slide)
+
+// -- * no editing should be needed below * -- //
+
+var originPosition = {};
+var is_animating = 0;
+var currentStripPosition = 0;
+var centeringPoint = 0;
+var rightScrollLimit = 0;
+
+// makeSlideStrip()
+// - figures out how many slides there are
+// - determines the centering point of the slide strip
+function makeSlideStrip() {
+  var slideTotal = 0;
+  centeringPoint = Math.ceil(slidesAtOnce/2);
+  for (var x in slideCode) {
+    slideTotal++;
+  }
+  var i = 0;
+  for (var code in slideCode) {
+    if (i <= centeringPoint-1) {
+      originPosition[code] = 0;
+    } else {
+      if (i >= slideTotal-centeringPoint+1)  {
+        originPosition[code] = (slideTotal-slidesAtOnce)*slideWidth;
+      } else {
+        originPosition[code] = (i-centeringPoint+1)*slideWidth;
+      }
+    }
+    i++;
+  }
+  rightScrollLimit = -1*(slideTotal-slidesAtOnce)*slideWidth;
+}
+
+// slides with acceleration
+function slide(goal, id, go_left, cp) {
+  var div = document.getElementById(id);
+  var animation = {};
+  animation.time = 0.5;  // in seconds
+  animation.fps = 60;
+  animation.goal = goal;
+  origin = 0.0;
+  animation.origin = Math.abs(origin);  
+  animation.frames = (animation.time * animation.fps) - 1.0;
+  var current_frame = 0;
+  var motions = Math.abs(animation.goal - animation.origin);
+  function animate() {
+    var ease_right = function (t) { return (1 - Math.cos(t * Math.PI))/2.0; };
+    var ease = ease_right;
+    if (go_left == 1) {
+      ease = function(t) { return 1.0 - ease_right(t); };
+    }
+    var left = (ease(current_frame/animation.frames) * Math.abs(animation.goal - animation.origin)) - cp; 
+    if(left < 0) {
+      left = 0;
+    }
+    if(!isNaN(left)) {
+      div.style.left = '-' + Math.round(left) + 'px';
+    }
+    current_frame += 1;
+    if (current_frame == animation.frames) {
+      is_animating = 0;
+      window.clearInterval(timeoutId)
+    }
+  }
+  var timeoutId = window.setInterval(animate, animation.time/animation.fps * 1000);
+}
+
+//Get style property
+function getStyle(element, cssProperty){
+  var elem = document.getElementById(element);
+  if(elem.currentStyle){
+    return elem.currentStyle[cssProperty]; //IE
+  } else{
+    var style =  document.defaultView.getComputedStyle(elem, null); //firefox, Opera
+    return style.getPropertyValue(cssProperty);
+  }
+}
+
+// Left and right arrows
+function page_left() {
+  var amount = slideWidth;
+  animateSlide(amount, 'left');
+}
+
+function page_right() { 
+  var amount = slideWidth;
+  animateSlide(amount, 'right');
+}
+
+
+// animates the strip
+// - sets arrows to on or off
+function animateSlide(amount,dir) {
+  var currentStripPosition = parseInt(getStyle(slideList,'left'));
+  var motionDistance;
+  if (amount == slideWidth ) {
+    motionDistance = slideWidth;
+  } else {
+    motionDistance = amount;
+  }
+  
+  var rightarrow = document.getElementById(arrowRight);
+  var leftarrow = document.getElementById(arrowLeft);
+  
+  function aToggle(state,aDir) {
+    if (state == 'on') {
+      if (aDir =='right') {
+        rightarrow.className = 'arrow-right-on';
+        rightarrow.href = "javascript:page_right()";
+      } else {
+        leftarrow.className = 'arrow-left-on';
+        leftarrow.href = "javascript:page_left()";
+      }
+    } else {
+      if (aDir =='right') {
+        rightarrow.href = "javascript:{}";
+        rightarrow.className = 'arrow-right-off'; 
+      } else {
+        leftarrow.href = "javascript:{}";
+        leftarrow.className = 'arrow-left-off';
+      }
+    }
+  }
+  
+  function arrowChange(rP) {
+    if (rP >= rightScrollLimit) {
+      aToggle('on','right');
+    }
+    if (rP <= rightScrollLimit) {
+      aToggle('off','right');
+    }
+    if (rP <= slideWidth) {
+      aToggle('on','left');
+    }
+    if (rP >= 0) {
+      aToggle('off','left');
+    }
+  }
+
+  if (dir == 'right' && is_animating == 0) {
+    arrowChange(currentStripPosition-motionDistance);
+    is_animating = 1;
+    slide(motionDistance, slideList, 0, currentStripPosition);
+  } else if (dir == 'left' && is_animating == 0) {
+    arrowChange(currentStripPosition+motionDistance);
+    is_animating = 1;
+    rightStripPosition = currentStripPosition + motionDistance;
+    slide(motionDistance, slideList, 1, rightStripPosition);
+  }
+}
+
+function centerSlide(slideName) {
+  var currentStripPosition = parseInt(getStyle(slideList,'left'));
+  var dir = 'left';
+  var originpoint = Math.abs(currentStripPosition);
+  if (originpoint <= originPosition[slideName]) {
+    dir = 'right';
+  }
+  var motionValue = Math.abs(originPosition[slideName]-originpoint);
+  animateSlide(motionValue,dir);
+}
+
+
+function initCarousel(def) {
+  buildCarousel();
+  showPreview(def);
+  makeSlideStrip();
+}
diff --git a/build/tools/droiddoc/templates/assets/images/android-developers-logo.png b/build/tools/droiddoc/templates/assets/images/android-developers-logo.png
new file mode 100644 (file)
index 0000000..30a8f62
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/android-developers-logo.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/android_wrench.png b/build/tools/droiddoc/templates/assets/images/android_wrench.png
new file mode 100644 (file)
index 0000000..6390a2d
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/android_wrench.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/arrow_bluelink_down.png b/build/tools/droiddoc/templates/assets/images/arrow_bluelink_down.png
new file mode 100644 (file)
index 0000000..58c248a
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/arrow_bluelink_down.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/arrow_bluelink_up.png b/build/tools/droiddoc/templates/assets/images/arrow_bluelink_up.png
new file mode 100644 (file)
index 0000000..7d0f38e
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/arrow_bluelink_up.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/arrow_left_off.jpg b/build/tools/droiddoc/templates/assets/images/arrow_left_off.jpg
new file mode 100644 (file)
index 0000000..fd32a64
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/arrow_left_off.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/arrow_left_on.jpg b/build/tools/droiddoc/templates/assets/images/arrow_left_on.jpg
new file mode 100644 (file)
index 0000000..143184b
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/arrow_left_on.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/arrow_right_off.jpg b/build/tools/droiddoc/templates/assets/images/arrow_right_off.jpg
new file mode 100644 (file)
index 0000000..17d2efe
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/arrow_right_off.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/arrow_right_on.jpg b/build/tools/droiddoc/templates/assets/images/arrow_right_on.jpg
new file mode 100644 (file)
index 0000000..baa2af1
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/arrow_right_on.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/bg_community_leftDiv.jpg b/build/tools/droiddoc/templates/assets/images/bg_community_leftDiv.jpg
new file mode 100644 (file)
index 0000000..a6d6f0e
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/bg_community_leftDiv.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/bg_fade.jpg b/build/tools/droiddoc/templates/assets/images/bg_fade.jpg
new file mode 100644 (file)
index 0000000..c6c70b6
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/bg_fade.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/bg_images_sprite.png b/build/tools/droiddoc/templates/assets/images/bg_images_sprite.png
new file mode 100644 (file)
index 0000000..84437e7
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/bg_images_sprite.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/bg_logo.png b/build/tools/droiddoc/templates/assets/images/bg_logo.png
new file mode 100644 (file)
index 0000000..8c57fc4
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/bg_logo.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/body-gradient-tab.png b/build/tools/droiddoc/templates/assets/images/body-gradient-tab.png
new file mode 100644 (file)
index 0000000..5223ac3
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/body-gradient-tab.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/body-gradient.png b/build/tools/droiddoc/templates/assets/images/body-gradient.png
new file mode 100644 (file)
index 0000000..9d59855
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/body-gradient.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/developers-logo.png b/build/tools/droiddoc/templates/assets/images/developers-logo.png
new file mode 100644 (file)
index 0000000..08122ee
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/developers-logo.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/grad-rule-qv.png b/build/tools/droiddoc/templates/assets/images/grad-rule-qv.png
new file mode 100644 (file)
index 0000000..bae2d18
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/grad-rule-qv.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/Android_Dev_Lab_l.png b/build/tools/droiddoc/templates/assets/images/home/Android_Dev_Lab_l.png
new file mode 100644 (file)
index 0000000..3c04f24
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/Android_Dev_Lab_l.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/IO-logo.png b/build/tools/droiddoc/templates/assets/images/home/IO-logo.png
new file mode 100644 (file)
index 0000000..65334c8
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/IO-logo.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/adc2_l.png b/build/tools/droiddoc/templates/assets/images/home/adc2_l.png
new file mode 100644 (file)
index 0000000..0b101a4
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/adc2_l.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/adc2_s.png b/build/tools/droiddoc/templates/assets/images/home/adc2_s.png
new file mode 100644 (file)
index 0000000..0d36bdb
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/adc2_s.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/android_adc.png b/build/tools/droiddoc/templates/assets/images/home/android_adc.png
new file mode 100644 (file)
index 0000000..9fe7f8f
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/android_adc.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/bg_home_announcement.png b/build/tools/droiddoc/templates/assets/images/home/bg_home_announcement.png
new file mode 100644 (file)
index 0000000..91485ff
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/bg_home_announcement.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/bg_home_bottom.jpg b/build/tools/droiddoc/templates/assets/images/home/bg_home_bottom.jpg
new file mode 100644 (file)
index 0000000..dacd401
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/bg_home_bottom.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/bg_home_carousel.png b/build/tools/droiddoc/templates/assets/images/home/bg_home_carousel.png
new file mode 100644 (file)
index 0000000..5ce5e30
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/bg_home_carousel.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/bg_home_carousel_board.png b/build/tools/droiddoc/templates/assets/images/home/bg_home_carousel_board.png
new file mode 100644 (file)
index 0000000..c577e02
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/bg_home_carousel_board.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/bg_home_carousel_wheel.png b/build/tools/droiddoc/templates/assets/images/home/bg_home_carousel_wheel.png
new file mode 100644 (file)
index 0000000..aa224ad
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/bg_home_carousel_wheel.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/carousel_buttons_sprite.png b/build/tools/droiddoc/templates/assets/images/home/carousel_buttons_sprite.png
new file mode 100644 (file)
index 0000000..e98c942
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/carousel_buttons_sprite.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/devphone-large.png b/build/tools/droiddoc/templates/assets/images/home/devphone-large.png
new file mode 100644 (file)
index 0000000..0db0f6c
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/devphone-large.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/devphone-small.png b/build/tools/droiddoc/templates/assets/images/home/devphone-small.png
new file mode 100644 (file)
index 0000000..e10bfa9
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/devphone-small.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/donut-android.png b/build/tools/droiddoc/templates/assets/images/home/donut-android.png
new file mode 100644 (file)
index 0000000..6aba06b
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/donut-android.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/eclair-android.png b/build/tools/droiddoc/templates/assets/images/home/eclair-android.png
new file mode 100644 (file)
index 0000000..d476ce9
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/eclair-android.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/froyo-android.png b/build/tools/droiddoc/templates/assets/images/home/froyo-android.png
new file mode 100644 (file)
index 0000000..c63f7f0
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/froyo-android.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/gdc-logo.png b/build/tools/droiddoc/templates/assets/images/home/gdc-logo.png
new file mode 100644 (file)
index 0000000..5fb53fb
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/gdc-logo.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/gingerdroid.png b/build/tools/droiddoc/templates/assets/images/home/gingerdroid.png
new file mode 100644 (file)
index 0000000..8399d84
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/gingerdroid.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/io-large.png b/build/tools/droiddoc/templates/assets/images/home/io-large.png
new file mode 100644 (file)
index 0000000..986053c
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/io-large.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/io-small.png b/build/tools/droiddoc/templates/assets/images/home/io-small.png
new file mode 100644 (file)
index 0000000..3a22549
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/io-small.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/maps-large.png b/build/tools/droiddoc/templates/assets/images/home/maps-large.png
new file mode 100644 (file)
index 0000000..b26f65a
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/maps-large.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/maps-small.png b/build/tools/droiddoc/templates/assets/images/home/maps-small.png
new file mode 100644 (file)
index 0000000..cc5f1fa
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/maps-small.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/market-large.png b/build/tools/droiddoc/templates/assets/images/home/market-large.png
new file mode 100644 (file)
index 0000000..069fee7
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/market-large.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/market-small.png b/build/tools/droiddoc/templates/assets/images/home/market-small.png
new file mode 100644 (file)
index 0000000..fa1201c
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/market-small.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/sdk-large.png b/build/tools/droiddoc/templates/assets/images/home/sdk-large.png
new file mode 100644 (file)
index 0000000..315a1bf
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/sdk-large.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/sdk-small.png b/build/tools/droiddoc/templates/assets/images/home/sdk-small.png
new file mode 100644 (file)
index 0000000..0f1670d
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/sdk-small.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/tv_l.png b/build/tools/droiddoc/templates/assets/images/home/tv_l.png
new file mode 100644 (file)
index 0000000..ed89bfc
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/tv_l.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/home/tv_s.png b/build/tools/droiddoc/templates/assets/images/home/tv_s.png
new file mode 100644 (file)
index 0000000..6ca68cb
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/home/tv_s.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/hr_gray_main.jpg b/build/tools/droiddoc/templates/assets/images/hr_gray_main.jpg
new file mode 100644 (file)
index 0000000..f7a0a2f
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/hr_gray_main.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/hr_gray_side.jpg b/build/tools/droiddoc/templates/assets/images/hr_gray_side.jpg
new file mode 100644 (file)
index 0000000..6667476
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/hr_gray_side.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/icon_contribute.jpg b/build/tools/droiddoc/templates/assets/images/icon_contribute.jpg
new file mode 100644 (file)
index 0000000..1aa12b6
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/icon_contribute.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/icon_download.jpg b/build/tools/droiddoc/templates/assets/images/icon_download.jpg
new file mode 100644 (file)
index 0000000..f8c1165
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/icon_download.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/icon_download2.jpg b/build/tools/droiddoc/templates/assets/images/icon_download2.jpg
new file mode 100644 (file)
index 0000000..c0af7a2
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/icon_download2.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/icon_guidelines_logo.png b/build/tools/droiddoc/templates/assets/images/icon_guidelines_logo.png
new file mode 100644 (file)
index 0000000..9362c8f
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/icon_guidelines_logo.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/icon_market.jpg b/build/tools/droiddoc/templates/assets/images/icon_market.jpg
new file mode 100644 (file)
index 0000000..225e727
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/icon_market.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/icon_robot.jpg b/build/tools/droiddoc/templates/assets/images/icon_robot.jpg
new file mode 100644 (file)
index 0000000..ca0fd39
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/icon_robot.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/icon_world.jpg b/build/tools/droiddoc/templates/assets/images/icon_world.jpg
new file mode 100644 (file)
index 0000000..65b8fa6
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/icon_world.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/left_off.jpg b/build/tools/droiddoc/templates/assets/images/left_off.jpg
new file mode 100644 (file)
index 0000000..fd32a64
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/left_off.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/left_on.jpg b/build/tools/droiddoc/templates/assets/images/left_on.jpg
new file mode 100644 (file)
index 0000000..143184b
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/left_on.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/logo_breadcrumbz.jpg b/build/tools/droiddoc/templates/assets/images/logo_breadcrumbz.jpg
new file mode 100644 (file)
index 0000000..e743f86
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/logo_breadcrumbz.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/open_source.png b/build/tools/droiddoc/templates/assets/images/open_source.png
new file mode 100644 (file)
index 0000000..12bb1fb
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/open_source.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/preliminary.png b/build/tools/droiddoc/templates/assets/images/preliminary.png
new file mode 100644 (file)
index 0000000..fe0da3d
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/preliminary.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/resizable-e.gif b/build/tools/droiddoc/templates/assets/images/resizable-e.gif
new file mode 100644 (file)
index 0000000..f748097
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/resizable-e.gif differ
diff --git a/build/tools/droiddoc/templates/assets/images/resizable-e2.gif b/build/tools/droiddoc/templates/assets/images/resizable-e2.gif
new file mode 100644 (file)
index 0000000..e45d0c5
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/resizable-e2.gif differ
diff --git a/build/tools/droiddoc/templates/assets/images/resizable-eg.gif b/build/tools/droiddoc/templates/assets/images/resizable-eg.gif
new file mode 100644 (file)
index 0000000..6196616
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/resizable-eg.gif differ
diff --git a/build/tools/droiddoc/templates/assets/images/resizable-s.gif b/build/tools/droiddoc/templates/assets/images/resizable-s.gif
new file mode 100644 (file)
index 0000000..7f6a4eb
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/resizable-s.gif differ
diff --git a/build/tools/droiddoc/templates/assets/images/resizable-s2.gif b/build/tools/droiddoc/templates/assets/images/resizable-s2.gif
new file mode 100644 (file)
index 0000000..99e869c
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/resizable-s2.gif differ
diff --git a/build/tools/droiddoc/templates/assets/images/resizable-sg.gif b/build/tools/droiddoc/templates/assets/images/resizable-sg.gif
new file mode 100644 (file)
index 0000000..b4bea10
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/resizable-sg.gif differ
diff --git a/build/tools/droiddoc/templates/assets/images/right_off.jpg b/build/tools/droiddoc/templates/assets/images/right_off.jpg
new file mode 100644 (file)
index 0000000..17d2efe
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/right_off.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/right_on.jpg b/build/tools/droiddoc/templates/assets/images/right_on.jpg
new file mode 100644 (file)
index 0000000..baa2af1
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/right_on.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/sidenav-rule.png b/build/tools/droiddoc/templates/assets/images/sidenav-rule.png
new file mode 100644 (file)
index 0000000..eab9920
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/sidenav-rule.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/slide_1.jpg b/build/tools/droiddoc/templates/assets/images/slide_1.jpg
new file mode 100644 (file)
index 0000000..6d75be1
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/slide_1.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/slide_2.jpg b/build/tools/droiddoc/templates/assets/images/slide_2.jpg
new file mode 100644 (file)
index 0000000..aa994c2
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/slide_2.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/slide_3.jpg b/build/tools/droiddoc/templates/assets/images/slide_3.jpg
new file mode 100644 (file)
index 0000000..b04deb3
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/slide_3.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/slide_large_1.jpg b/build/tools/droiddoc/templates/assets/images/slide_large_1.jpg
new file mode 100644 (file)
index 0000000..a992e92
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/slide_large_1.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/slide_large_2.jpg b/build/tools/droiddoc/templates/assets/images/slide_large_2.jpg
new file mode 100644 (file)
index 0000000..9af63f4
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/slide_large_2.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/slide_large_3.jpg b/build/tools/droiddoc/templates/assets/images/slide_large_3.jpg
new file mode 100644 (file)
index 0000000..fcf236c
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/slide_large_3.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/slide_off.jpg b/build/tools/droiddoc/templates/assets/images/slide_off.jpg
new file mode 100644 (file)
index 0000000..5971227
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/slide_off.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/slide_on.jpg b/build/tools/droiddoc/templates/assets/images/slide_on.jpg
new file mode 100644 (file)
index 0000000..7ca3577
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/slide_on.jpg differ
diff --git a/build/tools/droiddoc/templates/assets/images/spacer.gif b/build/tools/droiddoc/templates/assets/images/spacer.gif
new file mode 100644 (file)
index 0000000..f96b355
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/spacer.gif differ
diff --git a/build/tools/droiddoc/templates/assets/images/triangle-closed-small.png b/build/tools/droiddoc/templates/assets/images/triangle-closed-small.png
new file mode 100644 (file)
index 0000000..002364a
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/triangle-closed-small.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/triangle-closed.png b/build/tools/droiddoc/templates/assets/images/triangle-closed.png
new file mode 100644 (file)
index 0000000..a34a055
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/triangle-closed.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/triangle-opened-small.png b/build/tools/droiddoc/templates/assets/images/triangle-opened-small.png
new file mode 100644 (file)
index 0000000..e1eb784
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/triangle-opened-small.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/triangle-opened.png b/build/tools/droiddoc/templates/assets/images/triangle-opened.png
new file mode 100644 (file)
index 0000000..a709604
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/triangle-opened.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/uiguidelines1.png b/build/tools/droiddoc/templates/assets/images/uiguidelines1.png
new file mode 100644 (file)
index 0000000..5ce1611
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/uiguidelines1.png differ
diff --git a/build/tools/droiddoc/templates/assets/images/video-droid.png b/build/tools/droiddoc/templates/assets/images/video-droid.png
new file mode 100644 (file)
index 0000000..25163b6
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/images/video-droid.png differ
diff --git a/build/tools/droiddoc/templates/assets/jdiff_logo.gif b/build/tools/droiddoc/templates/assets/jdiff_logo.gif
new file mode 100644 (file)
index 0000000..6970087
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/jdiff_logo.gif differ
diff --git a/build/tools/droiddoc/templates/assets/jquery-history.js b/build/tools/droiddoc/templates/assets/jquery-history.js
new file mode 100644 (file)
index 0000000..ef96ec3
--- /dev/null
@@ -0,0 +1,78 @@
+/**
+ * jQuery history event v0.1
+ * Copyright (c) 2008 Tom Rodenberg <tarodenberg gmail com>
+ * Licensed under the GPL (http://www.gnu.org/licenses/gpl.html) license.
+ */
+(function($) {
+    var currentHash, previousNav, timer, hashTrim = /^.*#/;
+
+    var msie = {
+        iframe: null,
+        getDoc: function() {
+            return msie.iframe.contentWindow.document;
+        },
+        getHash: function() {
+            return msie.getDoc().location.hash;
+        },
+        setHash: function(hash) {
+            var d = msie.getDoc();
+            d.open();
+            d.close();
+            d.location.hash = hash;
+        }
+    };
+
+    var historycheck = function() {
+        var hash = msie.iframe ? msie.getHash() : location.hash;
+        if (hash != currentHash) {
+            currentHash = hash;
+            if (msie.iframe) {
+                location.hash = currentHash;
+            }
+            var current = $.history.getCurrent();
+            $.event.trigger('history', [current, previousNav]);
+            previousNav = current;
+        }
+    };
+
+    $.history = {
+        add: function(hash) {
+            hash = '#' + hash.replace(hashTrim, '');
+            if (currentHash != hash) {
+                var previous = $.history.getCurrent();
+                location.hash = currentHash = hash;
+                if (msie.iframe) {
+                    msie.setHash(currentHash);
+                }
+                $.event.trigger('historyadd', [$.history.getCurrent(), previous]);
+            }
+            if (!timer) {
+                timer = setInterval(historycheck, 100);
+            }
+        },
+        getCurrent: function() {
+            if (currentHash) {
+              return currentHash.replace(hashTrim, '');
+            } else { 
+              return ""; 
+            }
+        }
+    };
+
+    $.fn.history = function(fn) {
+        $(this).bind('history', fn);
+    };
+
+    $.fn.historyadd = function(fn) {
+        $(this).bind('historyadd', fn);
+    };
+
+    $(function() {
+        currentHash = location.hash;
+        if ($.browser.msie) {
+            msie.iframe = $('<iframe style="display:none" src="javascript:false;"></iframe>').prependTo('body')[0];
+            msie.setHash(currentHash);
+            currentHash = msie.getHash();
+        }
+    });
+})(jQuery);
diff --git a/build/tools/droiddoc/templates/assets/jquery-resizable.min.js b/build/tools/droiddoc/templates/assets/jquery-resizable.min.js
new file mode 100644 (file)
index 0000000..67186fe
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * jQuery JavaScript Library v1.3.2
+ * http://jquery.com/
+ *
+ * Copyright (c) 2009 John Resig
+ * Dual licensed under the MIT and GPL licenses.
+ * http://docs.jquery.com/License
+ *
+ * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
+ * Revision: 6246
+ */
+(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F<J;F++){var G=M[F];if(G.selected){K=o(G).val();if(H){return K}L.push(K)}}return L}return(E.value||"").replace(/\r/g,"")}return g}if(typeof K==="number"){K+=""}return this.each(function(){if(this.nodeType!=1){return}if(o.isArray(K)&&/radio|checkbox/.test(this.type)){this.checked=(o.inArray(this.value,K)>=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G<E;G++){L.call(K(this[G],H),this.length>1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H<I;H++){if((G=arguments[H])!=null){for(var F in G){var K=J[F],L=G[F];if(J===L){continue}if(E&&L&&typeof L==="object"&&!L.nodeType){J[F]=o.extend(E,K||(L.length!=null?[]:{}),L)}else{if(L!==g){J[F]=L}}}}}return J};var b=/z-?index|font-?weight|opacity|zoom|line-?height/i,q=document.defaultView||{},s=Object.prototype.toString;o.extend({noConflict:function(E){l.$=p;if(E){l.jQuery=y}return o},isFunction:function(E){return s.call(E)==="[object Function]"},isArray:function(E){return s.call(E)==="[object Array]"},isXMLDoc:function(E){return E.nodeType===9&&E.documentElement.nodeName!=="HTML"||!!E.ownerDocument&&o.isXMLDoc(E.ownerDocument)},globalEval:function(G){if(G&&/\S/.test(G)){var F=document.getElementsByTagName("head")[0]||document.documentElement,E=document.createElement("script");E.type="text/javascript";if(o.support.scriptEval){E.appendChild(document.createTextNode(G))}else{E.text=G}F.insertBefore(E,F.firstChild);F.removeChild(E)}},nodeName:function(F,E){return F.nodeName&&F.nodeName.toUpperCase()==E.toUpperCase()},each:function(G,K,F){var E,H=0,I=G.length;if(F){if(I===g){for(E in G){if(K.apply(G[E],F)===false){break}}}else{for(;H<I;){if(K.apply(G[H++],F)===false){break}}}}else{if(I===g){for(E in G){if(K.call(G[E],E,G[E])===false){break}}}else{for(var J=G[0];H<I&&K.call(J,H,J)!==false;J=G[++H]){}}}return G},prop:function(H,I,G,F,E){if(o.isFunction(I)){I=I.call(H,F)}return typeof I==="number"&&G=="curCSS"&&!b.test(E)?I+"px":I},className:{add:function(E,F){o.each((F||"").split(/\s+/),function(G,H){if(E.nodeType==1&&!o.className.has(E.className,H)){E.className+=(E.className?" ":"")+H}})},remove:function(E,F){if(E.nodeType==1){E.className=F!==g?o.grep(E.className.split(/\s+/),function(G){return !o.className.has(F,G)}).join(" "):""}},has:function(F,E){return F&&o.inArray(E,(F.className||F).toString().split(/\s+/))>-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+"></"+T+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!O.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!O.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!O.indexOf("<td")||!O.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!O.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||!o.support.htmlSerialize&&[1,"div<div>","</div>"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/<tbody/i.test(S),N=!O.indexOf("<table")&&!R?L.firstChild&&L.firstChild.childNodes:Q[1]=="<table>"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E<F;E++){if(H[E]===G){return E}}return -1},merge:function(H,E){var F=0,G,I=H.length;if(!o.support.getAll){while((G=E[F++])!=null){if(G.nodeType!=8){H[I++]=G}}}else{while((G=E[F++])!=null){H[I++]=G}}return H},unique:function(K){var F=[],E={};try{for(var G=0,H=K.length;G<H;G++){var J=o.data(K[G]);if(!E[J]){E[J]=true;F.push(K[G])}}}catch(I){F=K}return F},grep:function(F,J,E){var G=[];for(var H=0,I=F.length;H<I;H++){if(!E!=!J(F[H],H)){G.push(F[H])}}return G},map:function(E,J){var F=[];for(var G=0,H=E.length;G<H;G++){var I=J(E[G],G);if(I!=null){F[F.length]=I}}return F.concat.apply([],F)}});var C=navigator.userAgent.toLowerCase();o.browser={version:(C.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],safari:/webkit/.test(C),opera:/opera/.test(C),msie:/msie/.test(C)&&!/opera/.test(C),mozilla:/mozilla/.test(C)&&!/(compatible|webkit)/.test(C)};o.each({parent:function(E){return E.parentNode},parents:function(E){return o.dir(E,"parentNode")},next:function(E){return o.nth(E,2,"nextSibling")},prev:function(E){return o.nth(E,2,"previousSibling")},nextAll:function(E){return o.dir(E,"nextSibling")},prevAll:function(E){return o.dir(E,"previousSibling")},siblings:function(E){return o.sibling(E.parentNode.firstChild,E)},children:function(E){return o.sibling(E.firstChild)},contents:function(E){return o.nodeName(E,"iframe")?E.contentDocument||E.contentWindow.document:o.makeArray(E.childNodes)}},function(E,F){o.fn[E]=function(G){var H=o.map(this,F);if(G&&typeof G=="string"){H=o.multiFilter(G,H)}return this.pushStack(o.unique(H),E,G)}});o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(E,F){o.fn[E]=function(G){var J=[],L=o(G);for(var K=0,H=L.length;K<H;K++){var I=(K>0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}});
+/*
+ * Sizzle CSS Selector Engine - v0.9.3
+ *  Copyright 2009, The Dojo Foundation
+ *  Released under the MIT, BSD, and GPL Licenses.
+ *  More information: http://sizzlejs.com/
+ */
+(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa<ab.length;aa++){if(ab[aa]===ab[aa-1]){ab.splice(aa--,1)}}}}}return ab};F.matches=function(T,U){return F(T,null,null,U)};F.find=function(aa,T,ab){var Z,X;if(!aa){return[]}for(var W=0,V=I.order.length;W<V;W++){var Y=I.order[W],X;if((X=I.match[Y].exec(aa))){var U=RegExp.leftContext;if(U.substr(U.length-1)!=="\\"){X[1]=(X[1]||"").replace(/\\/g,"");Z=I.find[Y](X,T,ab);if(Z!=null){aa=aa.replace(I.match[Y],"");break}}}}if(!Z){Z=T.getElementsByTagName("*")}return{set:Z,expr:aa}};F.filter=function(ad,ac,ag,W){var V=ad,ai=[],aa=ac,Y,T,Z=ac&&ac[0]&&Q(ac[0]);while(ad&&ac.length){for(var ab in I.filter){if((Y=I.match[ab].exec(ad))!=null){var U=I.filter[ab],ah,af;T=false;if(aa==ai){ai=[]}if(I.preFilter[ab]){Y=I.preFilter[ab](Y,aa,ag,ai,W,Z);if(!Y){T=ah=true}else{if(Y===true){continue}}}if(Y){for(var X=0;(af=aa[X])!=null;X++){if(af){ah=U(af,Y,X,aa);var ae=W^!!ah;if(ag&&ah!=null){if(ae){T=true}else{aa[X]=false}}else{if(ae){ai.push(af);T=true}}}}}if(ah!==g){if(!ag){aa=ai}ad=ad.replace(I.match[ab],"");if(!T){return[]}break}}}if(ad==V){if(T==null){throw"Syntax error, unrecognized expression: "+ad}else{break}}V=ad}return aa};var I=F.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(T){return T.getAttribute("href")}},relative:{"+":function(aa,T,Z){var X=typeof T==="string",ab=X&&!/\W/.test(T),Y=X&&!ab;if(ab&&!Z){T=T.toUpperCase()}for(var W=0,V=aa.length,U;W<V;W++){if((U=aa[W])){while((U=U.previousSibling)&&U.nodeType!==1){}aa[W]=Y||U&&U.nodeName===T?U||false:U===T}}if(Y){F.filter(T,aa,true)}},">":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){var W=Y.parentNode;Z[V]=W.nodeName===U?W:false}}}else{for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){Z[V]=X?Y.parentNode:Y.parentNode===U}}if(X){F.filter(U,Z,true)}}},"":function(W,U,Y){var V=L++,T=S;if(!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("parentNode",U,V,W,X,Y)},"~":function(W,U,Y){var V=L++,T=S;if(typeof U==="string"&&!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("previousSibling",U,V,W,X,Y)}},find:{ID:function(U,V,W){if(typeof V.getElementById!=="undefined"&&!W){var T=V.getElementById(U[1]);return T?[T]:[]}},NAME:function(V,Y,Z){if(typeof Y.getElementsByName!=="undefined"){var U=[],X=Y.getElementsByName(V[1]);for(var W=0,T=X.length;W<T;W++){if(X[W].getAttribute("name")===V[1]){U.push(X[W])}}return U.length===0?null:U}},TAG:function(T,U){return U.getElementsByTagName(T[1])}},preFilter:{CLASS:function(W,U,V,T,Z,aa){W=" "+W[1].replace(/\\/g,"")+" ";if(aa){return W}for(var X=0,Y;(Y=U[X])!=null;X++){if(Y){if(Z^(Y.className&&(" "+Y.className+" ").indexOf(W)>=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return U<T[3]-0},gt:function(V,U,T){return U>T[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W<T;W++){if(Y[W]===Z){return false}}return true}}}},CHILD:function(T,W){var Z=W[1],U=T;switch(Z){case"only":case"first":while(U=U.previousSibling){if(U.nodeType===1){return false}}if(Z=="first"){return true}U=T;case"last":while(U=U.nextSibling){if(U.nodeType===1){return false}}return true;case"nth":var V=W[2],ac=W[3];if(V==1&&ac==0){return true}var Y=W[0],ab=T.parentNode;if(ab&&(ab.sizcache!==Y||!T.nodeIndex)){var X=0;for(U=ab.firstChild;U;U=U.nextSibling){if(U.nodeType===1){U.nodeIndex=++X}}ab.sizcache=Y}var aa=T.nodeIndex-ac;if(V==0){return aa==0}else{return(aa%V==0&&aa/V>=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V<T;V++){U.push(X[V])}}else{for(var V=0;X[V];V++){U.push(X[V])}}}return U}}var G;if(document.documentElement.compareDocumentPosition){G=function(U,T){var V=U.compareDocumentPosition(T)&4?-1:U===T?0:1;if(V===0){hasDuplicate=true}return V}}else{if("sourceIndex" in document.documentElement){G=function(U,T){var V=U.sourceIndex-T.sourceIndex;if(V===0){hasDuplicate=true}return V}}else{if(document.createRange){G=function(W,U){var V=W.ownerDocument.createRange(),T=U.ownerDocument.createRange();V.selectNode(W);V.collapse(true);T.selectNode(U);T.collapse(true);var X=V.compareBoundaryPoints(Range.START_TO_END,T);if(X===0){hasDuplicate=true}return X}}}}(function(){var U=document.createElement("form"),V="script"+(new Date).getTime();U.innerHTML="<input name='"+V+"'/>";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="<a href='#'></a>";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="<p class='TEST'></p>";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="<div class='test e'></div><div class='test'></div>";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1&&!ac){T.sizcache=Y;T.sizset=W}if(T.nodeName===Z){X=T;break}T=T[U]}ad[W]=X}}}function S(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1){if(!ac){T.sizcache=Y;T.sizset=W}if(typeof Z!=="string"){if(T===Z){X=true;break}}else{if(F.filter(Z,[T]).length>0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z<U;Z++){F(T,V[Z],W)}return F.filter(X,W)};o.find=F;o.filter=F.filter;o.expr=F.selectors;o.expr[":"]=o.expr.filters;F.selectors.filters.hidden=function(T){return T.offsetWidth===0||T.offsetHeight===0};F.selectors.filters.visible=function(T){return T.offsetWidth>0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F<E.length){o.event.proxy(G,E[F++])}return this.click(o.event.proxy(G,function(H){this.lastToggle=(this.lastToggle||0)%F;H.preventDefault();return E[this.lastToggle++].apply(this,arguments)||false}))},hover:function(E,F){return this.mouseenter(E).mouseleave(F)},ready:function(E){B();if(o.isReady){E.call(document,o)}else{o.readyList.push(E)}return this},live:function(G,F){var E=o.event.proxy(F);E.guid+=this.selector+G;o(document).bind(i(G,this.selector),this.selector,E);return this},die:function(F,E){o(document).unbind(i(F,this.selector),E?{guid:E.guid+this.selector+F}:null);return this}});function c(H){var E=RegExp("(^|\\.)"+H.type+"(\\.|$)"),G=true,F=[];o.each(o.data(this,"events").live||[],function(I,J){if(E.test(J.type)){var K=o(H.target).closest(J.data)[0];if(K){F.push({elem:K,fn:J})}}});F.sort(function(J,I){return o.data(J.elem,"closest")-o.data(I.elem,"closest")});o.each(F,function(){if(this.fn.call(this.elem,H,this.fn.data)===false){return(G=false)}});return G}function i(F,E){return["live",F,E.replace(/\./g,"`").replace(/ /g,"|")].join(".")}o.extend({isReady:false,readyList:[],ready:function(){if(!o.isReady){o.isReady=true;if(o.readyList){o.each(o.readyList,function(){this.call(document,o)});o.readyList=null}o(document).triggerHandler("ready")}}});var x=false;function B(){if(x){return}x=true;if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);o.ready()},false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);o.ready()}});if(document.documentElement.doScroll&&l==l.top){(function(){if(o.isReady){return}try{document.documentElement.doScroll("left")}catch(E){setTimeout(arguments.callee,0);return}o.ready()})()}}}o.event.add(l,"load",o.ready)}o.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(F,E){o.fn[E]=function(G){return G?this.bind(E,G):this.trigger(E)}});o(l).bind("unload",function(){for(var E in o.cache){if(E!=1&&o.cache[E].handle){o.event.remove(o.cache[E].handle.elem)}}});(function(){o.support={};var F=document.documentElement,G=document.createElement("script"),K=document.createElement("div"),J="script"+(new Date).getTime();K.style.display="none";K.innerHTML='   <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';var H=K.getElementsByTagName("*"),E=K.getElementsByTagName("a")[0];if(!H||!H.length||!E){return}o.support={leadingWhitespace:K.firstChild.nodeType==3,tbody:!K.getElementsByTagName("tbody").length,objectAll:!!K.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!K.getElementsByTagName("link").length,style:/red/.test(E.getAttribute("style")),hrefNormalized:E.getAttribute("href")==="/a",opacity:E.style.opacity==="0.5",cssFloat:!!E.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};G.type="text/javascript";try{G.appendChild(document.createTextNode("window."+J+"=1;"))}catch(I){}F.insertBefore(G,F.firstChild);if(l[J]){o.support.scriptEval=true;delete l[J]}F.removeChild(G);if(K.attachEvent&&K.fireEvent){K.attachEvent("onclick",function(){o.support.noCloneEvent=false;K.detachEvent("onclick",arguments.callee)});K.cloneNode(true).fireEvent("onclick")}o(function(){var L=document.createElement("div");L.style.width=L.style.paddingLeft="1px";document.body.appendChild(L);o.boxModel=o.support.boxModel=L.offsetWidth===2;document.body.removeChild(L).style.display="none"})})();var w=o.support.cssFloat?"cssFloat":"styleFloat";o.props={"for":"htmlFor","class":"className","float":w,cssFloat:w,styleFloat:w,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};o.fn.extend({_load:o.fn.load,load:function(G,J,K){if(typeof G!=="string"){return this._load(G)}var I=G.indexOf(" ");if(I>=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("<div/>").append(M.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H<F;H++){var E=o.data(this[H],"olddisplay");this[H].style.display=E||"";if(o.css(this[H],"display")==="none"){var G=this[H].tagName,K;if(m[G]){K=m[G]}else{var I=o("<"+G+" />").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H<F;H++){this[H].style.display=o.data(this[H],"olddisplay")||""}return this}},hide:function(H,I){if(H){return this.animate(t("hide",3),H,I)}else{for(var G=0,F=this.length;G<F;G++){var E=o.data(this[G],"olddisplay");if(!E&&E!=="none"){o.data(this[G],"olddisplay",o.css(this[G],"display"))}}for(var G=0,F=this.length;G<F;G++){this[G].style.display="none"}return this}},_toggle:o.fn.toggle,toggle:function(G,F){var E=typeof G==="boolean";return o.isFunction(G)&&o.isFunction(F)?this._toggle.apply(this,arguments):G==null||E?this.each(function(){var H=E?G:o(this).is(":hidden");o(this)[H?"show":"hide"]()}):this.animate(t("toggle",3),G,F)},fadeTo:function(E,G,F){return this.animate({opacity:G},E,F)},animate:function(I,F,H,G){var E=o.speed(F,H,G);return this[E.queue===false?"each":"queue"](function(){var K=o.extend({},E),M,L=this.nodeType==1&&o(this).is(":hidden"),J=this;for(M in I){if(I[M]=="hide"&&L||I[M]=="show"&&!L){return K.complete.call(this)}if((M=="height"||M=="width")&&this.style){K.display=o.css(this,"display");K.overflow=this.style.overflow}}if(K.overflow!=null){this.style.overflow="hidden"}K.curAnim=o.extend({},I);o.each(I,function(O,S){var R=new o.fx(J,K,O);if(/toggle|show|hide/.test(S)){R[S=="toggle"?L?"show":"hide":S](I)}else{var Q=S.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),T=R.cur(true)||0;if(Q){var N=parseFloat(Q[2]),P=Q[3]||"px";if(P!="px"){J.style[O]=(N||1)+P;T=((N||1)/R.cur(true))*T;J.style[O]=T+P}if(Q[1]){N=((Q[1]=="-="?-1:1)*N)+T}R.custom(T,N,P)}else{R.custom(T,S,"")}}});return true})},stop:function(F,E){var G=o.timers;if(F){this.queue([])}this.each(function(){for(var H=G.length-1;H>=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J<K.length;J++){if(!K[J]()){K.splice(J--,1)}}if(!K.length){clearInterval(n);n=g}},13)}},show:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.show=true;this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());o(this.elem).show()},hide:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(H){var G=e();if(H||G>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})();
+/*
+ * jQuery UI 1.7.2
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI
+ */
+jQuery.ui||(function(c){var i=c.fn.remove,d=c.browser.mozilla&&(parseFloat(c.browser.version)<1.9);c.ui={version:"1.7.2",plugin:{add:function(k,l,n){var m=c.ui[k].prototype;for(var j in n){m.plugins[j]=m.plugins[j]||[];m.plugins[j].push([l,n[j]])}},call:function(j,l,k){var n=j.plugins[l];if(!n||!j.element[0].parentNode){return}for(var m=0;m<n.length;m++){if(j.options[n[m][0]]){n[m][1].apply(j.element,k)}}}},contains:function(k,j){return document.compareDocumentPosition?k.compareDocumentPosition(j)&16:k!==j&&k.contains(j)},hasScroll:function(m,k){if(c(m).css("overflow")=="hidden"){return false}var j=(k&&k=="left")?"scrollLeft":"scrollTop",l=false;if(m[j]>0){return true}m[j]=1;l=(m[j]>0);m[j]=0;return l},isOverAxis:function(k,j,l){return(k>j)&&(k<(j+l))},isOver:function(o,k,n,m,j,l){return c.ui.isOverAxis(o,n,j)&&c.ui.isOverAxis(k,m,l)},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};if(d){var f=c.attr,e=c.fn.removeAttr,h="http://www.w3.org/2005/07/aaa",a=/^aria-/,b=/^wairole:/;c.attr=function(k,j,l){var m=l!==undefined;return(j=="role"?(m?f.call(this,k,j,"wairole:"+l):(f.apply(this,arguments)||"").replace(b,"")):(a.test(j)?(m?k.setAttributeNS(h,j.replace(a,"aaa:"),l):f.call(this,k,j.replace(a,"aaa:"))):f.apply(this,arguments)))};c.fn.removeAttr=function(j){return(a.test(j)?this.each(function(){this.removeAttributeNS(h,j.replace(a,""))}):e.call(this,j))}}c.fn.extend({remove:function(){c("*",this).add(this).each(function(){c(this).triggerHandler("remove")});return i.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","").unbind("selectstart.ui")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return false})},scrollParent:function(){var j;if((c.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){j=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(c.curCSS(this,"position",1))&&(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}else{j=this.parents().filter(function(){return(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!j.length?c(document):j}});c.extend(c.expr[":"],{data:function(l,k,j){return !!c.data(l,j[3])},focusable:function(k){var l=k.nodeName.toLowerCase(),j=c.attr(k,"tabindex");return(/input|select|textarea|button|object/.test(l)?!k.disabled:"a"==l||"area"==l?k.href||!isNaN(j):!isNaN(j))&&!c(k)["area"==l?"parents":"closest"](":hidden").length},tabbable:function(k){var j=c.attr(k,"tabindex");return(isNaN(j)||j>=0)&&c(k).is(":focusable")}});function g(m,n,o,l){function k(q){var p=c[m][n][q]||[];return(typeof p=="string"?p.split(/,?\s+/):p)}var j=k("getter");if(l.length==1&&typeof l[0]=="string"){j=j.concat(k("getterSetter"))}return(c.inArray(o,j)!=-1)}c.widget=function(k,j){var l=k.split(".")[0];k=k.split(".")[1];c.fn[k]=function(p){var n=(typeof p=="string"),o=Array.prototype.slice.call(arguments,1);if(n&&p.substring(0,1)=="_"){return this}if(n&&g(l,k,p,o)){var m=c.data(this[0],k);return(m?m[p].apply(m,o):undefined)}return this.each(function(){var q=c.data(this,k);(!q&&!n&&c.data(this,k,new c[l][k](this,p))._init());(q&&n&&c.isFunction(q[p])&&q[p].apply(q,o))})};c[l]=c[l]||{};c[l][k]=function(o,n){var m=this;this.namespace=l;this.widgetName=k;this.widgetEventPrefix=c[l][k].eventPrefix||k;this.widgetBaseClass=l+"-"+k;this.options=c.extend({},c.widget.defaults,c[l][k].defaults,c.metadata&&c.metadata.get(o)[k],n);this.element=c(o).bind("setData."+k,function(q,p,r){if(q.target==o){return m._setData(p,r)}}).bind("getData."+k,function(q,p){if(q.target==o){return m._getData(p)}}).bind("remove",function(){return m.destroy()})};c[l][k].prototype=c.extend({},c.widget.prototype,j);c[l][k].getterSetter="option"};c.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").removeAttr("aria-disabled")},option:function(l,m){var k=l,j=this;if(typeof l=="string"){if(m===undefined){return this._getData(l)}k={};k[l]=m}c.each(k,function(n,o){j._setData(n,o)})},_getData:function(j){return this.options[j]},_setData:function(j,k){this.options[j]=k;if(j=="disabled"){this.element[k?"addClass":"removeClass"](this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").attr("aria-disabled",k)}},enable:function(){this._setData("disabled",false)},disable:function(){this._setData("disabled",true)},_trigger:function(l,m,n){var p=this.options[l],j=(l==this.widgetEventPrefix?l:this.widgetEventPrefix+l);m=c.Event(m);m.type=j;if(m.originalEvent){for(var k=c.event.props.length,o;k;){o=c.event.props[--k];m[o]=m.originalEvent[o]}}this.element.trigger(m,n);return !(c.isFunction(p)&&p.call(this.element[0],m,n)===false||m.isDefaultPrevented())}};c.widget.defaults={disabled:false};c.ui.mouse={_mouseInit:function(){var j=this;this.element.bind("mousedown."+this.widgetName,function(k){return j._mouseDown(k)}).bind("click."+this.widgetName,function(k){if(j._preventClickEvent){j._preventClickEvent=false;k.stopImmediatePropagation();return false}});if(c.browser.msie){this._mouseUnselectable=this.element.attr("unselectable");this.element.attr("unselectable","on")}this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName);(c.browser.msie&&this.element.attr("unselectable",this._mouseUnselectable))},_mouseDown:function(l){l.originalEvent=l.originalEvent||{};if(l.originalEvent.mouseHandled){return}(this._mouseStarted&&this._mouseUp(l));this._mouseDownEvent=l;var k=this,m=(l.which==1),j=(typeof this.options.cancel=="string"?c(l.target).parents().add(l.target).filter(this.options.cancel).length:false);if(!m||j||!this._mouseCapture(l)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){k.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(l)&&this._mouseDelayMet(l)){this._mouseStarted=(this._mouseStart(l)!==false);if(!this._mouseStarted){l.preventDefault();return true}}this._mouseMoveDelegate=function(n){return k._mouseMove(n)};this._mouseUpDelegate=function(n){return k._mouseUp(n)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);(c.browser.safari||l.preventDefault());l.originalEvent.mouseHandled=true;return true},_mouseMove:function(j){if(c.browser.msie&&!j.button){return this._mouseUp(j)}if(this._mouseStarted){this._mouseDrag(j);return j.preventDefault()}if(this._mouseDistanceMet(j)&&this._mouseDelayMet(j)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,j)!==false);(this._mouseStarted?this._mouseDrag(j):this._mouseUp(j))}return !this._mouseStarted},_mouseUp:function(j){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=(j.target==this._mouseDownEvent.target);this._mouseStop(j)}return false},_mouseDistanceMet:function(j){return(Math.max(Math.abs(this._mouseDownEvent.pageX-j.pageX),Math.abs(this._mouseDownEvent.pageY-j.pageY))>=this.options.distance)},_mouseDelayMet:function(j){return this.mouseDelayMet},_mouseStart:function(j){},_mouseDrag:function(j){},_mouseStop:function(j){},_mouseCapture:function(j){return true}};c.ui.mouse.defaults={cancel:null,distance:1,delay:0}})(jQuery);;/* * jQuery UI Resizable 1.7.2
+ *
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Resizables
+ *
+ * Depends:
+ *     ui.core.js
+ */
+(function(c){c.widget("ui.resizable",c.extend({},c.ui.mouse,{_init:function(){var e=this,j=this.options;this.element.addClass("ui-resizable");c.extend(this,{_aspectRatio:!!(j.aspectRatio),aspectRatio:j.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:j.helper||j.ghost||j.animate?j.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){if(/relative/.test(this.element.css("position"))&&c.browser.opera){this.element.css({position:"relative",top:"auto",left:"auto"})}this.element.wrap(c('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=j.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var k=this.handles.split(",");this.handles={};for(var f=0;f<k.length;f++){var h=c.trim(k[f]),d="ui-resizable-"+h;var g=c('<div class="ui-resizable-handle '+d+'"></div>');if(/sw|se|ne|nw/.test(h)){g.css({zIndex:++j.zIndex})}if("se"==h){g.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[h]=".ui-resizable-"+h;this.element.append(g)}}this._renderAxis=function(p){p=p||this.element;for(var m in this.handles){if(this.handles[m].constructor==String){this.handles[m]=c(this.handles[m],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var n=c(this.handles[m],this.element),o=0;o=/sw|ne|nw|se|n|s/.test(m)?n.outerHeight():n.outerWidth();var l=["padding",/ne|nw|n/.test(m)?"Top":/se|sw|s/.test(m)?"Bottom":/^e$/.test(m)?"Right":"Left"].join("");p.css(l,o);this._proportionallyResize()}if(!c(this.handles[m]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!e.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}e.axis=i&&i[1]?i[1]:"se"}});if(j.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){c(this).removeClass("ui-resizable-autohide");e._handles.show()},function(){if(!e.resizing){c(this).addClass("ui-resizable-autohide");e._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var d=function(f){c(f).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){d(this.element);var e=this.element;e.parent().append(this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")})).end().remove()}this.originalElement.css("resize",this.originalResizeStyle);d(this.originalElement)},_mouseCapture:function(e){var f=false;for(var d in this.handles){if(c(this.handles[d])[0]==e.target){f=true}}return this.options.disabled||!!f},_mouseStart:function(f){var i=this.options,e=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(d.is(".ui-draggable")||(/absolute/).test(d.css("position"))){d.css({position:"absolute",top:e.top,left:e.left})}if(c.browser.opera&&(/relative/).test(d.css("position"))){d.css({position:"relative",top:"auto",left:"auto"})}this._renderProxy();var j=b(this.helper.css("left")),g=b(this.helper.css("top"));if(i.containment){j+=c(i.containment).scrollLeft()||0;g+=c(i.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:j,top:g};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:j,top:g};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:f.pageX,top:f.pageY};this.aspectRatio=(typeof i.aspectRatio=="number")?i.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var h=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",h=="auto"?this.axis+"-resize":h);d.addClass("ui-resizable-resizing");this._propagate("start",f);return true},_mouseDrag:function(d){var g=this.helper,f=this.options,l={},p=this,i=this.originalMousePosition,m=this.axis;var q=(d.pageX-i.left)||0,n=(d.pageY-i.top)||0;var h=this._change[m];if(!h){return false}var k=h.apply(this,[d,q,n]),j=c.browser.msie&&c.browser.version<7,e=this.sizeDiff;if(this._aspectRatio||d.shiftKey){k=this._updateRatio(k,d)}k=this._respectSize(k,d);this._propagate("resize",d);g.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(k);this._trigger("resize",d,this.ui());return false},_mouseStop:function(g){this.resizing=false;var h=this.options,l=this;if(this._helper){var f=this._proportionallyResizeElements,d=f.length&&(/textarea/i).test(f[0].nodeName),e=d&&c.ui.hasScroll(f[0],"left")?0:l.sizeDiff.height,j=d?0:l.sizeDiff.width;var m={width:(l.size.width-j),height:(l.size.height-e)},i=(parseInt(l.element.css("left"),10)+(l.position.left-l.originalPosition.left))||null,k=(parseInt(l.element.css("top"),10)+(l.position.top-l.originalPosition.top))||null;if(!h.animate){this.element.css(c.extend(m,{top:k,left:i}))}l.helper.height(l.size.height);l.helper.width(l.size.width);if(this._helper&&!h.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",g);if(this._helper){this.helper.remove()}return false},_updateCache:function(d){var e=this.options;this.offset=this.helper.offset();if(a(d.left)){this.position.left=d.left}if(a(d.top)){this.position.top=d.top}if(a(d.height)){this.size.height=d.height}if(a(d.width)){this.size.width=d.width}},_updateRatio:function(g,f){var h=this.options,i=this.position,e=this.size,d=this.axis;if(g.height){g.width=(e.height*this.aspectRatio)}else{if(g.width){g.height=(e.width/this.aspectRatio)}}if(d=="sw"){g.left=i.left+(e.width-g.width);g.top=null}if(d=="nw"){g.top=i.top+(e.height-g.height);g.left=i.left+(e.width-g.width)}return g},_respectSize:function(k,f){var i=this.helper,h=this.options,q=this._aspectRatio||f.shiftKey,p=this.axis,s=a(k.width)&&h.maxWidth&&(h.maxWidth<k.width),l=a(k.height)&&h.maxHeight&&(h.maxHeight<k.height),g=a(k.width)&&h.minWidth&&(h.minWidth>k.width),r=a(k.height)&&h.minHeight&&(h.minHeight>k.height);if(g){k.width=h.minWidth}if(r){k.height=h.minHeight}if(s){k.width=h.maxWidth}if(l){k.height=h.maxHeight}var e=this.originalPosition.left+this.originalSize.width,n=this.position.top+this.size.height;var j=/sw|nw|w/.test(p),d=/nw|ne|n/.test(p);if(g&&j){k.left=e-h.minWidth}if(s&&j){k.left=e-h.maxWidth}if(r&&d){k.top=n-h.minHeight}if(l&&d){k.top=n-h.maxHeight}var m=!k.width&&!k.height;if(m&&!k.left&&k.top){k.top=null}else{if(m&&!k.top&&k.left){k.left=null}}return k},_proportionallyResize:function(){var j=this.options;if(!this._proportionallyResizeElements.length){return}var f=this.helper||this.element;for(var e=0;e<this._proportionallyResizeElements.length;e++){var g=this._proportionallyResizeElements[e];if(!this.borderDif){var d=[g.css("borderTopWidth"),g.css("borderRightWidth"),g.css("borderBottomWidth"),g.css("borderLeftWidth")],h=[g.css("paddingTop"),g.css("paddingRight"),g.css("paddingBottom"),g.css("paddingLeft")];this.borderDif=c.map(d,function(k,m){var l=parseInt(k,10)||0,n=parseInt(h[m],10)||0;return l+n})}if(c.browser.msie&&!(!(c(f).is(":hidden")||c(f).parents(":hidden").length))){continue}g.css({height:(f.height()-this.borderDif[0]-this.borderDif[2])||0,width:(f.width()-this.borderDif[1]-this.borderDif[3])||0})}},_renderProxy:function(){var e=this.element,h=this.options;this.elementOffset=e.offset();if(this._helper){this.helper=this.helper||c('<div style="overflow:hidden;"></div>');var d=c.browser.msie&&c.browser.version<7,f=(d?1:0),g=(d?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+g,height:this.element.outerHeight()+g,position:"absolute",left:this.elementOffset.left-f+"px",top:this.elementOffset.top-f+"px",zIndex:++h.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(f,e,d){return{width:this.originalSize.width+e}},w:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{left:h.left+e,width:f.width-e}},n:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{top:h.top+d,height:f.height-d}},s:function(f,e,d){return{height:this.originalSize.height+d}},se:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},sw:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[f,e,d]))},ne:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},nw:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[f,e,d]))}},_propagate:function(e,d){c.ui.plugin.call(this,e,[d,this.ui()]);(e!="resize"&&this._trigger(e,d,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}));c.extend(c.ui.resizable,{version:"1.7.2",eventPrefix:"resize",defaults:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,cancel:":input,option",containment:false,delay:0,distance:1,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000}});c.ui.plugin.add("resizable","alsoResize",{start:function(e,f){var d=c(this).data("resizable"),g=d.options;_store=function(h){c(h).each(function(){c(this).data("resizable-alsoresize",{width:parseInt(c(this).width(),10),height:parseInt(c(this).height(),10),left:parseInt(c(this).css("left"),10),top:parseInt(c(this).css("top"),10)})})};if(typeof(g.alsoResize)=="object"&&!g.alsoResize.parentNode){if(g.alsoResize.length){g.alsoResize=g.alsoResize[0];_store(g.alsoResize)}else{c.each(g.alsoResize,function(h,i){_store(h)})}}else{_store(g.alsoResize)}},resize:function(f,h){var e=c(this).data("resizable"),i=e.options,g=e.originalSize,k=e.originalPosition;var j={height:(e.size.height-g.height)||0,width:(e.size.width-g.width)||0,top:(e.position.top-k.top)||0,left:(e.position.left-k.left)||0},d=function(l,m){c(l).each(function(){var p=c(this),q=c(this).data("resizable-alsoresize"),o={},n=m&&m.length?m:["width","height","top","left"];c.each(n||["width","height","top","left"],function(r,t){var s=(q[t]||0)+(j[t]||0);if(s&&s>=0){o[t]=s||null}});if(/relative/.test(p.css("position"))&&c.browser.opera){e._revertToRelativePosition=true;p.css({position:"absolute",top:"auto",left:"auto"})}p.css(o)})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.nodeType){c.each(i.alsoResize,function(l,m){d(l,m)})}else{d(i.alsoResize)}},stop:function(e,f){var d=c(this).data("resizable");if(d._revertToRelativePosition&&c.browser.opera){d._revertToRelativePosition=false;el.css({position:"relative"})}c(this).removeData("resizable-alsoresize-start")}});c.ui.plugin.add("resizable","animate",{stop:function(h,m){var n=c(this).data("resizable"),i=n.options;var g=n._proportionallyResizeElements,d=g.length&&(/textarea/i).test(g[0].nodeName),e=d&&c.ui.hasScroll(g[0],"left")?0:n.sizeDiff.height,k=d?0:n.sizeDiff.width;var f={width:(n.size.width-k),height:(n.size.height-e)},j=(parseInt(n.element.css("left"),10)+(n.position.left-n.originalPosition.left))||null,l=(parseInt(n.element.css("top"),10)+(n.position.top-n.originalPosition.top))||null;n.element.animate(c.extend(f,l&&j?{top:l,left:j}:{}),{duration:i.animateDuration,easing:i.animateEasing,step:function(){var o={width:parseInt(n.element.css("width"),10),height:parseInt(n.element.css("height"),10),top:parseInt(n.element.css("top"),10),left:parseInt(n.element.css("left"),10)};if(g&&g.length){c(g[0]).css({width:o.width,height:o.height})}n._updateCache(o);n._propagate("resize",h)}})}});c.ui.plugin.add("resizable","containment",{start:function(e,q){var s=c(this).data("resizable"),i=s.options,k=s.element;var f=i.containment,j=(f instanceof c)?f.get(0):(/parent/.test(f))?k.parent().get(0):f;if(!j){return}s.containerElement=c(j);if(/document/.test(f)||f==document){s.containerOffset={left:0,top:0};s.containerPosition={left:0,top:0};s.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var m=c(j),h=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){h[p]=b(m.css("padding"+o))});s.containerOffset=m.offset();s.containerPosition=m.position();s.containerSize={height:(m.innerHeight()-h[3]),width:(m.innerWidth()-h[1])};var n=s.containerOffset,d=s.containerSize.height,l=s.containerSize.width,g=(c.ui.hasScroll(j,"left")?j.scrollWidth:l),r=(c.ui.hasScroll(j)?j.scrollHeight:d);s.parentData={element:j,left:n.left,top:n.top,width:g,height:r}}},resize:function(f,p){var s=c(this).data("resizable"),h=s.options,e=s.containerSize,n=s.containerOffset,l=s.size,m=s.position,q=s._aspectRatio||f.shiftKey,d={top:0,left:0},g=s.containerElement;if(g[0]!=document&&(/static/).test(g.css("position"))){d=n}if(m.left<(s._helper?n.left:0)){s.size.width=s.size.width+(s._helper?(s.position.left-n.left):(s.position.left-d.left));if(q){s.size.height=s.size.width/h.aspectRatio}s.position.left=h.helper?n.left:0}if(m.top<(s._helper?n.top:0)){s.size.height=s.size.height+(s._helper?(s.position.top-n.top):s.position.top);if(q){s.size.width=s.size.height*h.aspectRatio}s.position.top=s._helper?n.top:0}s.offset.left=s.parentData.left+s.position.left;s.offset.top=s.parentData.top+s.position.top;var k=Math.abs((s._helper?s.offset.left-d.left:(s.offset.left-d.left))+s.sizeDiff.width),r=Math.abs((s._helper?s.offset.top-d.top:(s.offset.top-n.top))+s.sizeDiff.height);var j=s.containerElement.get(0)==s.element.parent().get(0),i=/relative|absolute/.test(s.containerElement.css("position"));if(j&&i){k-=s.parentData.left}if(k+s.size.width>=s.parentData.width){s.size.width=s.parentData.width-k;if(q){s.size.height=s.size.width/s.aspectRatio}}if(r+s.size.height>=s.parentData.height){s.size.height=s.parentData.height-r;if(q){s.size.width=s.size.height*s.aspectRatio}}},stop:function(e,m){var p=c(this).data("resizable"),f=p.options,k=p.position,l=p.containerOffset,d=p.containerPosition,g=p.containerElement;var i=c(p.helper),q=i.offset(),n=i.outerWidth()-p.sizeDiff.width,j=i.outerHeight()-p.sizeDiff.height;if(p._helper&&!f.animate&&(/relative/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}if(p._helper&&!f.animate&&(/static/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}}});c.ui.plugin.add("resizable","ghost",{start:function(f,g){var d=c(this).data("resizable"),h=d.options,e=d.size;d.ghost=d.originalElement.clone();d.ghost.css({opacity:0.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof h.ghost=="string"?h.ghost:"");d.ghost.appendTo(d.helper)},resize:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost){d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})}},stop:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost&&d.helper){d.helper.get(0).removeChild(d.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(d,l){var n=c(this).data("resizable"),g=n.options,j=n.size,h=n.originalSize,i=n.originalPosition,m=n.axis,k=g._aspectRatio||d.shiftKey;g.grid=typeof g.grid=="number"?[g.grid,g.grid]:g.grid;var f=Math.round((j.width-h.width)/(g.grid[0]||1))*(g.grid[0]||1),e=Math.round((j.height-h.height)/(g.grid[1]||1))*(g.grid[1]||1);if(/^(se|s|e)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e}else{if(/^(ne)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e}else{if(/^(sw)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.left=i.left-f}else{n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e;n.position.left=i.left-f}}}}});var b=function(d){return parseInt(d,10)||0};var a=function(d){return !isNaN(parseInt(d,10))}})(jQuery);;
diff --git a/build/tools/droiddoc/templates/assets/prettify.js b/build/tools/droiddoc/templates/assets/prettify.js
new file mode 100644 (file)
index 0000000..076f9d0
--- /dev/null
@@ -0,0 +1,33 @@
+(function(){
+var o=true,r=null,z=false;window.PR_SHOULD_USE_CONTINUATION=o;window.PR_TAB_WIDTH=8;window.PR_normalizedHtml=window.PR=window.prettyPrintOne=window.prettyPrint=void 0;window._pr_isIE6=function(){var N=navigator&&navigator.userAgent&&/\bMSIE 6\./.test(navigator.userAgent);window._pr_isIE6=function(){return N};return N};
+var aa="!",ba="!=",ca="!==",F="#",da="%",ea="%=",G="&",fa="&&",ja="&&=",ka="&=",H="(",la="*",ma="*=",na="+=",oa=",",pa="-=",qa="->",ra="/",sa="/=",ta=":",ua="::",va=";",I="<",wa="<<",xa="<<=",ya="<=",za="=",Aa="==",Ba="===",J=">",Ca=">=",Da=">>",Ea=">>=",Fa=">>>",Ga=">>>=",Ha="?",Ia="@",L="[",M="^",Ta="^=",Ua="^^",Va="^^=",Wa="{",O="|",Xa="|=",Ya="||",Za="||=",$a="~",ab="break",bb="case",cb="continue",db="delete",eb="do",fb="else",gb="finally",hb="instanceof",ib="return",jb="throw",kb="try",lb="typeof",
+mb="(?:^^|[+-]",nb="\\$1",ob=")\\s*",pb="&amp;",qb="&lt;",rb="&gt;",sb="&quot;",tb="&#",ub="x",vb="'",wb='"',xb=" ",yb="XMP",zb="</",Ab='="',P="",Q="\\",Bb="b",Cb="t",Db="n",Eb="v",Fb="f",Gb="r",Hb="u",Ib="0",Jb="1",Kb="2",Lb="3",Mb="4",Nb="5",Ob="6",Pb="7",Qb="\\x0",Rb="\\x",Sb="-",Tb="]",Ub="\\\\u[0-9A-Fa-f]{4}|\\\\x[0-9A-Fa-f]{2}|\\\\[0-3][0-7]{0,2}|\\\\[0-7]{1,2}|\\\\[\\s\\S]|-|[^-\\\\]",R="g",Vb="\\B",Wb="\\b",Xb="\\D",Yb="\\d",Zb="\\S",$b="\\s",ac="\\W",bc="\\w",cc="(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)",
+dc="(?:",ec=")",fc="gi",gc="PRE",hc='<!DOCTYPE foo PUBLIC "foo bar">\n<foo />',ic="\t",jc="\n",kc="[^<]+|<!--[\\s\\S]*?--\>|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>|</?[a-zA-Z][^>]*>|<",lc="nocode",mc=' $1="$2$3$4"',S="pln",nc="string",T="lang-",oc="src",U="str",pc="'\"",qc="'\"`",rc="\"'",V="com",sc="lang-regex",tc="(/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/)",uc="kwd",vc="^(?:",wc=")\\b",xc=" \r\n\t\u00a0",yc="lit",zc="typ",Ac="0123456789",Y="pun",Bc="break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try alignof align_union asm axiom bool concept concept_map const_cast constexpr decltype dynamic_cast explicit export friend inline late_check mutable namespace nullptr reinterpret_cast static_assert static_cast template typeid typename typeof using virtual wchar_t where break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try boolean byte extends final finally implements import instanceof null native package strictfp super synchronized throws transient as base by checked decimal delegate descending event fixed foreach from group implicit in interface internal into is lock object out override orderby params partial readonly ref sbyte sealed stackalloc string select uint ulong unchecked unsafe ushort var break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try debugger eval export function get null set undefined var with Infinity NaN caller delete die do dump elsif eval exit foreach for goto if import last local my next no our print package redo require sub undef unless until use wantarray while BEGIN END break continue do else for if return while and as assert class def del elif except exec finally from global import in is lambda nonlocal not or pass print raise try with yield False True None break continue do else for if return while alias and begin case class def defined elsif end ensure false in module next nil not or redo rescue retry self super then true undef unless until when yield BEGIN END break continue do else for if return while case done elif esac eval fi function in local set then until ",
+Cc="</span>",Dc='<span class="',Ec='">',Fc="$1&nbsp;",Gc="&nbsp;<br />",Hc="<br />",Ic="console",Jc="cannot override language handler %s",Kc="default-markup",Lc="default-code",Mc="dec",Z="lang-js",$="lang-css",Nc="lang-in.tag",Oc="htm",Pc="html",Qc="mxml",Rc="xhtml",Sc="xml",Tc="xsl",Uc=" \t\r\n",Vc="atv",Wc="tag",Xc="atn",Yc="lang-uq.val",Zc="in.tag",$c="uq.val",ad="break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try alignof align_union asm axiom bool concept concept_map const_cast constexpr decltype dynamic_cast explicit export friend inline late_check mutable namespace nullptr reinterpret_cast static_assert static_cast template typeid typename typeof using virtual wchar_t where ",
+bd="c",cd="cc",dd="cpp",ed="cxx",fd="cyc",gd="m",hd="null true false",id="json",jd="break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try boolean byte extends final finally implements import instanceof null native package strictfp super synchronized throws transient as base by checked decimal delegate descending event fixed foreach from group implicit in interface internal into is lock object out override orderby params partial readonly ref sbyte sealed stackalloc string select uint ulong unchecked unsafe ushort var ",
+kd="cs",ld="break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try boolean byte extends final finally implements import instanceof null native package strictfp super synchronized throws transient ",md="java",nd="break continue do else for if return while case done elif esac eval fi function in local set then until ",
+od="bsh",pd="csh",qd="sh",rd="break continue do else for if return while and as assert class def del elif except exec finally from global import in is lambda nonlocal not or pass print raise try with yield False True None ",sd="cv",td="py",ud="caller delete die do dump elsif eval exit foreach for goto if import last local my next no our print package redo require sub undef unless until use wantarray while BEGIN END ",vd="perl",wd="pl",xd="pm",yd="break continue do else for if return while alias and begin case class def defined elsif end ensure false in module next nil not or redo rescue retry self super then true undef unless until when yield BEGIN END ",
+zd="rb",Ad="break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try debugger eval export function get null set undefined var with Infinity NaN ",Bd="js",Cd="regex",Dd="pre",Ed="code",Fd="xmp",Gd="prettyprint",Hd="class",Id="br",Jd="\r";
+(function(){var N=function(){for(var a=[aa,ba,ca,F,da,ea,G,fa,ja,ka,H,la,ma,na,oa,pa,qa,ra,sa,ta,ua,va,I,wa,xa,ya,za,Aa,Ba,J,Ca,Da,Ea,Fa,Ga,Ha,Ia,L,M,Ta,Ua,Va,Wa,O,Xa,Ya,Za,$a,ab,bb,cb,db,eb,fb,gb,hb,ib,jb,kb,lb],b=mb,c=0;c<a.length;++c)b+=O+a[c].replace(/([^=<>:&a-z])/g,nb);b+=ob;return b}(),Ja=/&/g,Ka=/</g,La=/>/g,Kd=/\"/g;function Ld(a){return a.replace(Ja,pb).replace(Ka,qb).replace(La,rb).replace(Kd,sb)}function ga(a){return a.replace(Ja,pb).replace(Ka,qb).replace(La,rb)}var Md=/&lt;/g,Nd=/&gt;/g,
+Od=/&apos;/g,Pd=/&quot;/g,Qd=/&amp;/g,Rd=/&nbsp;/g;function Sd(a){var b=a.indexOf(G);if(b<0)return a;for(--b;(b=a.indexOf(tb,b+1))>=0;){var c=a.indexOf(va,b);if(c>=0){var d=a.substring(b+3,c),g=10;if(d&&d.charAt(0)===ub){d=d.substring(1);g=16}var i=parseInt(d,g);isNaN(i)||(a=a.substring(0,b)+String.fromCharCode(i)+a.substring(c+1))}}return a.replace(Md,I).replace(Nd,J).replace(Od,vb).replace(Pd,wb).replace(Qd,G).replace(Rd,xb)}function Ma(a){return yb===a.tagName}function W(a,b){switch(a.nodeType){case 1:var c=
+a.tagName.toLowerCase();b.push(I,c);for(var d=0;d<a.attributes.length;++d){var g=a.attributes[d];if(g.specified){b.push(xb);W(g,b)}}b.push(J);for(var i=a.firstChild;i;i=i.nextSibling)W(i,b);if(a.firstChild||!/^(?:br|link|img)$/.test(c))b.push(zb,c,J);break;case 2:b.push(a.name.toLowerCase(),Ab,Ld(a.value),wb);break;case 3:case 4:b.push(ga(a.nodeValue));break}}function Na(a){for(var b=0,c=z,d=z,g=0,i=a.length;g<i;++g){var m=a[g];if(m.ignoreCase)d=o;else if(/[a-z]/i.test(m.source.replace(/\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi,
+P))){c=o;d=z;break}}function l(j){if(j.charAt(0)!==Q)return j.charCodeAt(0);switch(j.charAt(1)){case Bb:return 8;case Cb:return 9;case Db:return 10;case Eb:return 11;case Fb:return 12;case Gb:return 13;case Hb:case ub:return parseInt(j.substring(2),16)||j.charCodeAt(1);case Ib:case Jb:case Kb:case Lb:case Mb:case Nb:case Ob:case Pb:return parseInt(j.substring(1),8);default:return j.charCodeAt(1)}}function n(j){if(j<32)return(j<16?Qb:Rb)+j.toString(16);var f=String.fromCharCode(j);if(f===Q||f===Sb||
+f===L||f===Tb)f=Q+f;return f}function q(j){for(var f=j.substring(1,j.length-1).match(new RegExp(Ub,R)),s=[],k=[],h=f[0]===M,e=h?1:0,p=f.length;e<p;++e){var t=f[e];switch(t){case Vb:case Wb:case Xb:case Yb:case Zb:case $b:case ac:case bc:s.push(t);continue}var u=l(t),x;if(e+2<p&&Sb===f[e+1]){x=l(f[e+2]);e+=2}else x=u;k.push([u,x]);if(!(x<65||u>122)){x<65||u>90||k.push([Math.max(65,u)|32,Math.min(x,90)|32]);x<97||u>122||k.push([Math.max(97,u)&-33,Math.min(x,122)&-33])}}k.sort(function(Oa,Pa){return Oa[0]-
+Pa[0]||Pa[1]-Oa[1]});var B=[],E=[NaN,NaN];for(e=0;e<k.length;++e){var A=k[e];if(A[0]<=E[1]+1)E[1]=Math.max(E[1],A[1]);else B.push(E=A)}var D=[L];h&&D.push(M);D.push.apply(D,s);for(e=0;e<B.length;++e){A=B[e];D.push(n(A[0]));if(A[1]>A[0]){A[1]+1>A[0]&&D.push(Sb);D.push(n(A[1]))}}D.push(Tb);return D.join(P)}function v(j){var f=j.source.match(new RegExp(cc,R)),s=f.length,k=[],h,e=0;for(h=0;e<s;++e){var p=f[e];if(p===H)++h;else if(Q===p.charAt(0)){var t=+p.substring(1);if(t&&t<=h)k[t]=-1}}for(e=1;e<k.length;++e)if(-1===
+k[e])k[e]=++b;for(h=e=0;e<s;++e){p=f[e];if(p===H){++h;if(k[h]===undefined)f[e]=dc}else if(Q===p.charAt(0))if((t=+p.substring(1))&&t<=h)f[e]=Q+k[h]}for(h=e=0;e<s;++e)if(M===f[e]&&M!==f[e+1])f[e]=P;if(j.ignoreCase&&c)for(e=0;e<s;++e){p=f[e];var u=p.charAt(0);if(p.length>=2&&u===L)f[e]=q(p);else if(u!==Q)f[e]=p.replace(/[a-zA-Z]/g,function(x){var B=x.charCodeAt(0);return L+String.fromCharCode(B&-33,B|32)+Tb})}return f.join(P)}var w=[];g=0;for(i=a.length;g<i;++g){m=a[g];if(m.global||m.multiline)throw new Error(P+
+m);w.push(dc+v(m)+ec)}return new RegExp(w.join(O),d?fc:R)}var ha=r;function Td(a){if(r===ha){var b=document.createElement(gc);b.appendChild(document.createTextNode(hc));ha=!/</.test(b.innerHTML)}if(ha){var c=a.innerHTML;if(Ma(a))c=ga(c);return c}for(var d=[],g=a.firstChild;g;g=g.nextSibling)W(g,d);return d.join(P)}function Ud(a){var b=0;return function(c){for(var d=r,g=0,i=0,m=c.length;i<m;++i){var l=c.charAt(i);switch(l){case ic:d||(d=[]);d.push(c.substring(g,i));var n=a-b%a;for(b+=n;n>=0;n-="                ".length)d.push("                ".substring(0,
+n));g=i+1;break;case jc:b=0;break;default:++b}}if(!d)return c;d.push(c.substring(g));return d.join(P)}}var Vd=new RegExp(kc,R),Wd=/^<\!--/,Xd=/^<\[CDATA\[/,Yd=/^<br\b/i,Qa=/^<(\/?)([a-zA-Z]+)/;function Zd(a){var b=a.match(Vd),c=[],d=0,g=[];if(b)for(var i=0,m=b.length;i<m;++i){var l=b[i];if(l.length>1&&l.charAt(0)===I){if(!Wd.test(l))if(Xd.test(l)){c.push(l.substring(9,l.length-3));d+=l.length-12}else if(Yd.test(l)){c.push(jc);++d}else if(l.indexOf(lc)>=0&&$d(l)){var n=l.match(Qa)[2],q=1,v;v=i+1;a:for(;v<
+m;++v){var w=b[v].match(Qa);if(w&&w[2]===n)if(w[1]===ra){if(--q===0)break a}else++q}if(v<m){g.push(d,b.slice(i,v+1).join(P));i=v}else g.push(d,l)}else g.push(d,l)}else{var j=Sd(l);c.push(j);d+=j.length}}return{source:c.join(P),tags:g}}function $d(a){return!!a.replace(/\s(\w+)\s*=\s*(?:\"([^\"]*)\"|'([^\']*)'|(\S+))/g,mc).match(/[cC][lL][aA][sS][sS]=\"[^\"]*\bnocode\b/)}function ia(a,b,c,d){if(b){var g={source:b,b:a};c(g);d.push.apply(d,g.c)}}function K(a,b){var c={},d;(function(){for(var m=a.concat(b),
+l=[],n={},q=0,v=m.length;q<v;++q){var w=m[q],j=w[3];if(j)for(var f=j.length;--f>=0;)c[j.charAt(f)]=w;var s=w[1],k=P+s;if(!n.hasOwnProperty(k)){l.push(s);n[k]=r}}l.push(/[\0-\uffff]/);d=Na(l)})();var g=b.length,i=function(m){for(var l=m.source,n=m.b,q=[n,S],v=0,w=l.match(d)||[],j={},f=0,s=w.length;f<s;++f){var k=w[f],h=j[k],e,p;if(typeof h===nc)p=z;else{var t=c[k.charAt(0)];if(t){e=k.match(t[1]);h=t[0]}else{for(var u=0;u<g;++u){t=b[u];if(e=k.match(t[1])){h=t[0];break}}e||(h=S)}if((p=h.length>=5&&T===
+h.substring(0,5))&&!(e&&e[1])){p=z;h=oc}p||(j[k]=h)}var x=v;v+=k.length;if(p){var B=e[1],E=k.indexOf(B),A=E+B.length,D=h.substring(5);ia(n+x,k.substring(0,E),i,q);ia(n+x+E,B,Ra(D,B),q);ia(n+x+A,k.substring(A),i,q)}else q.push(n+x,h)}m.c=q};return i}function C(a){var b=[],c=[];if(a.tripleQuotedStrings)b.push([U,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,r,pc]);
+else a.multiLineStrings?b.push([U,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,r,qc]):b.push([U,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,r,rc]);if(a.hashComments)a.cStyleComments?b.push([V,/^#(?:[^\r\n\/]|\/(?!\*)|\/\*[^\r\n]*?\*\/)*/,r,F]):b.push([V,/^#[^\r\n]*/,r,F]);if(a.cStyleComments){c.push([V,/^\/\/[^\r\n]*/,r]);c.push([V,/^\/\*[\s\S]*?(?:\*\/|$)/,r])}a.regexLiterals&&c.push([sc,new RegExp(M+N+tc)]);var d=
+a.keywords.replace(/^\s+|\s+$/g,P);d.length&&c.push([uc,new RegExp(vc+d.replace(/\s+/g,O)+wc),r]);b.push([S,/^\s+/,r,xc]);c.push([yc,/^@[a-z_$][a-z_$@0-9]*/i,r,Ia],[zc,/^@?[A-Z]+[a-z][A-Za-z_$@0-9]*/,r],[S,/^[a-z_$][a-z_$@0-9]*/i,r],[yc,/^(?:0x[a-f0-9]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+\-]?\d+)?)[a-z]*/i,r,Ac],[Y,/^.[^\s\w\.$@\'\"\`\/\#]*/,r]);return K(b,c)}var ae=C({keywords:Bc,hashComments:o,cStyleComments:o,multiLineStrings:o,regexLiterals:o});function be(a){var b=a.source,c=a.f,d=a.c,
+g=[],i=0,m=r,l=r,n=0,q=0,v=Ud(window.PR_TAB_WIDTH),w=/([\r\n ]) /g,j=/(^| ) /gm,f=/\r\n?|\n/g,s=/[ \r\n]$/,k=o;function h(p){if(p>i){if(m&&m!==l){g.push(Cc);m=r}if(!m&&l){m=l;g.push(Dc,m,Ec)}var t=ga(v(b.substring(i,p))).replace(k?j:w,Fc);k=s.test(t);var u=window._pr_isIE6()?Gc:Hc;g.push(t.replace(f,u));i=p}}for(;1;){var e;if(e=n<c.length?q<d.length?c[n]<=d[q]:o:z){h(c[n]);if(m){g.push(Cc);m=r}g.push(c[n+1]);n+=2}else if(q<d.length){h(d[q]);l=d[q+1];q+=2}else break}h(b.length);m&&g.push(Cc);a.a=g.join(P)}
+var X={};function y(a,b){for(var c=b.length;--c>=0;){var d=b[c];if(X.hasOwnProperty(d))Ic in window&&console.i(Jc,d);else X[d]=a}}function Ra(a,b){a&&X.hasOwnProperty(a)||(a=/^\s*</.test(b)?Kc:Lc);return X[a]}y(ae,[Lc]);y(K([],[[S,/^[^<?]+/],[Mc,/^<!\w[^>]*(?:>|$)/],[V,/^<\!--[\s\S]*?(?:-\->|$)/],[T,/^<\?([\s\S]+?)(?:\?>|$)/],[T,/^<%([\s\S]+?)(?:%>|$)/],[Y,/^(?:<[%?]|[%?]>)/],[T,/^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],[Z,/^<script\b[^>]*>([\s\S]+?)<\/script\b[^>]*>/i],[$,/^<style\b[^>]*>([\s\S]+?)<\/style\b[^>]*>/i],
+[Nc,/^(<\/?[a-z][^<>]*>)/i]]),[Kc,Oc,Pc,Qc,Rc,Sc,Tc]);y(K([[S,/^[\s]+/,r,Uc],[Vc,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,r,rc]],[[Wc,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[Xc,/^(?!style\b|on)[a-z](?:[\w:-]*\w)?/],[Yc,/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[Y,/^[=<>\/]+/],[Z,/^on\w+\s*=\s*\"([^\"]+)\"/i],[Z,/^on\w+\s*=\s*\'([^\']+)\'/i],[Z,/^on\w+\s*=\s*([^\"\'>\s]+)/i],[$,/^sty\w+\s*=\s*\"([^\"]+)\"/i],[$,/^sty\w+\s*=\s*\'([^\']+)\'/i],[$,/^sty\w+\s*=\s*([^\"\'>\s]+)/i]]),[Zc]);y(K([],[[Vc,/^[\s\S]+/]]),
+[$c]);y(C({keywords:ad,hashComments:o,cStyleComments:o}),[bd,cd,dd,ed,fd,gd]);y(C({keywords:hd}),[id]);y(C({keywords:jd,hashComments:o,cStyleComments:o}),[kd]);y(C({keywords:ld,cStyleComments:o}),[md]);y(C({keywords:nd,hashComments:o,multiLineStrings:o}),[od,pd,qd]);y(C({keywords:rd,hashComments:o,multiLineStrings:o,tripleQuotedStrings:o}),[sd,td]);y(C({keywords:ud,hashComments:o,multiLineStrings:o,regexLiterals:o}),[vd,wd,xd]);y(C({keywords:yd,hashComments:o,multiLineStrings:o,regexLiterals:o}),
+[zd]);y(C({keywords:Ad,cStyleComments:o,regexLiterals:o}),[Bd]);y(K([],[[U,/^[\s\S]+/]]),[Cd]);function Sa(a){var b=a.e,c=a.d;a.a=b;try{var d=Zd(b),g=d.source;a.source=g;a.b=0;a.f=d.tags;Ra(c,g)(a);be(a)}catch(i){if(Ic in window){console.log(i);console.h()}}}function ce(a,b){var c={e:a,d:b};Sa(c);return c.a}function de(a){for(var b=window._pr_isIE6(),c=[document.getElementsByTagName(Dd),document.getElementsByTagName(Ed),document.getElementsByTagName(Fd)],d=[],g=0;g<c.length;++g)for(var i=0,m=c[g].length;i<
+m;++i)d.push(c[g][i]);c=r;var l=Date;l.now||(l={now:function(){return(new Date).getTime()}});var n=0,q;function v(){for(var j=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;n<d.length&&l.now()<j;n++){var f=d[n];if(f.className&&f.className.indexOf(Gd)>=0){var s=f.className.match(/\blang-(\w+)\b/);if(s)s=s[1];for(var k=z,h=f.parentNode;h;h=h.parentNode)if((h.tagName===Dd||h.tagName===Ed||h.tagName===Fd)&&h.className&&h.className.indexOf(Gd)>=0){k=o;break}if(!k){var e=Td(f);e=e.replace(/(?:\r\n?|\n)$/,
+P);q={e:e,d:s,g:f};Sa(q);w()}}}if(n<d.length)setTimeout(v,250);else a&&a()}function w(){var j=q.a;if(j){var f=q.g;if(Ma(f)){for(var s=document.createElement(gc),k=0;k<f.attributes.length;++k){var h=f.attributes[k];if(h.specified){var e=h.name.toLowerCase();if(e===Hd)s.className=h.value;else s.setAttribute(h.name,h.value)}}s.innerHTML=j;f.parentNode.replaceChild(s,f);f=s}else f.innerHTML=j;if(b&&f.tagName===gc)for(var p=f.getElementsByTagName(Id),t=p.length;--t>=0;){var u=p[t];u.parentNode.replaceChild(document.createTextNode(Jd),
+u)}}}v()}window.PR_normalizedHtml=W;window.prettyPrintOne=ce;window.prettyPrint=de;window.PR={combinePrefixPatterns:Na,createSimpleLexer:K,registerLangHandler:y,sourceDecorator:C,PR_ATTRIB_NAME:Xc,PR_ATTRIB_VALUE:Vc,PR_COMMENT:V,PR_DECLARATION:Mc,PR_KEYWORD:uc,PR_LITERAL:yc,PR_NOCODE:lc,PR_PLAIN:S,PR_PUNCTUATION:Y,PR_SOURCE:oc,PR_STRING:U,PR_TAG:Wc,PR_TYPE:zc}})();
+})()
diff --git a/build/tools/droiddoc/templates/assets/search_autocomplete.js b/build/tools/droiddoc/templates/assets/search_autocomplete.js
new file mode 100644 (file)
index 0000000..dd4552f
--- /dev/null
@@ -0,0 +1,266 @@
+var gSelectedIndex = -1;
+var gSelectedID = -1;
+var gMatches = new Array();
+var gLastText = "";
+var ROW_COUNT = 20;
+var gInitialized = false;
+var DEFAULT_TEXT = "search developer docs";
+
+function set_row_selected(row, selected)
+{
+    var c1 = row.cells[0];
+  //  var c2 = row.cells[1];
+    if (selected) {
+        c1.className = "jd-autocomplete jd-selected";
+  //      c2.className = "jd-autocomplete jd-selected jd-linktype";
+    } else {
+        c1.className = "jd-autocomplete";
+  //      c2.className = "jd-autocomplete jd-linktype";
+    }
+}
+
+function set_row_values(toroot, row, match)
+{
+    var link = row.cells[0].childNodes[0];
+    link.innerHTML = match.__hilabel || match.label;
+    link.href = toroot + match.link
+  //  row.cells[1].innerHTML = match.type;
+}
+
+function sync_selection_table(toroot)
+{
+    var filtered = document.getElementById("search_filtered");
+    var r; //TR DOM object
+    var i; //TR iterator
+    gSelectedID = -1;
+
+    filtered.onmouseover = function() { 
+        if(gSelectedIndex >= 0) {
+          set_row_selected(this.rows[gSelectedIndex], false);
+          gSelectedIndex = -1;
+        }
+    }
+
+    //initialize the table; draw it for the first time (but not visible).
+    if (!gInitialized) {
+        for (i=0; i<ROW_COUNT; i++) {
+            var r = filtered.insertRow(-1);
+            var c1 = r.insertCell(-1);
+        //    var c2 = r.insertCell(-1);
+            c1.className = "jd-autocomplete";
+         //   c2.className = "jd-autocomplete jd-linktype";
+            var link = document.createElement("a");
+            c1.onmousedown = function() {
+                window.location = this.firstChild.getAttribute("href");
+            }
+            c1.onmouseover = function() {
+                this.className = this.className + " jd-selected";
+            }
+            c1.onmouseout = function() {
+                this.className = "jd-autocomplete";
+            }
+            c1.appendChild(link);
+        }
+  /*      var r = filtered.insertRow(-1);
+        var c1 = r.insertCell(-1);
+        c1.className = "jd-autocomplete jd-linktype";
+        c1.colSpan = 2; */
+        gInitialized = true;
+    }
+
+    //if we have results, make the table visible and initialize result info
+    if (gMatches.length > 0) {
+        document.getElementById("search_filtered_div").className = "showing";
+        var N = gMatches.length < ROW_COUNT ? gMatches.length : ROW_COUNT;
+        for (i=0; i<N; i++) {
+            r = filtered.rows[i];
+            r.className = "show-row";
+            set_row_values(toroot, r, gMatches[i]);
+            set_row_selected(r, i == gSelectedIndex);
+            if (i == gSelectedIndex) {
+                gSelectedID = gMatches[i].id;
+            }
+        }
+        //start hiding rows that are no longer matches
+        for (; i<ROW_COUNT; i++) {
+            r = filtered.rows[i];
+            r.className = "no-display";
+        }
+        //if there are more results we're not showing, so say so.
+/*      if (gMatches.length > ROW_COUNT) {
+            r = filtered.rows[ROW_COUNT];
+            r.className = "show-row";
+            c1 = r.cells[0];
+            c1.innerHTML = "plus " + (gMatches.length-ROW_COUNT) + " more"; 
+        } else {
+            filtered.rows[ROW_COUNT].className = "hide-row";
+        }*/
+    //if we have no results, hide the table
+    } else {
+        document.getElementById("search_filtered_div").className = "no-display";
+    }
+}
+
+function search_changed(e, kd, toroot)
+{
+    var search = document.getElementById("search_autocomplete");
+    var text = search.value.replace(/(^ +)|( +$)/g, '');
+
+    // 13 = enter
+    if (e.keyCode == 13) {
+        document.getElementById("search_filtered_div").className = "no-display";
+        if (kd && gSelectedIndex >= 0) {
+            window.location = toroot + gMatches[gSelectedIndex].link;
+            return false;
+        } else if (gSelectedIndex < 0) {
+            return true;
+        }
+    }
+    // 38 -- arrow up
+    else if (kd && (e.keyCode == 38)) {
+        if (gSelectedIndex >= 0) {
+            gSelectedIndex--;
+        }
+        sync_selection_table(toroot);
+        return false;
+    }
+    // 40 -- arrow down
+    else if (kd && (e.keyCode == 40)) {
+        if (gSelectedIndex < gMatches.length-1
+                        && gSelectedIndex < ROW_COUNT-1) {
+            gSelectedIndex++;
+        }
+        sync_selection_table(toroot);
+        return false;
+    }
+    else if (!kd) {
+        gMatches = new Array();
+        matchedCount = 0;
+        gSelectedIndex = -1;
+        for (var i=0; i<DATA.length; i++) {
+            var s = DATA[i];
+            if (text.length != 0 &&
+                  s.label.toLowerCase().indexOf(text.toLowerCase()) != -1) {
+                gMatches[matchedCount] = s;
+                matchedCount++;
+            }
+        }
+        rank_autocomplete_results(text);
+        for (var i=0; i<gMatches.length; i++) {
+            var s = gMatches[i];
+            if (gSelectedID == s.id) {
+                gSelectedIndex = i;
+            }
+        }
+        highlight_autocomplete_result_labels(text);
+        sync_selection_table(toroot);
+        return true; // allow the event to bubble up to the search api
+    }
+}
+
+function rank_autocomplete_results(query) {
+    query = query || '';
+    if (!gMatches || !gMatches.length)
+      return;
+
+    // helper function that gets the last occurence index of the given regex
+    // in the given string, or -1 if not found
+    var _lastSearch = function(s, re) {
+      if (s == '')
+        return -1;
+      var l = -1;
+      var tmp;
+      while ((tmp = s.search(re)) >= 0) {
+        if (l < 0) l = 0;
+        l += tmp;
+        s = s.substr(tmp + 1);
+      }
+      return l;
+    };
+
+    // helper function that counts the occurrences of a given character in
+    // a given string
+    var _countChar = function(s, c) {
+      var n = 0;
+      for (var i=0; i<s.length; i++)
+        if (s.charAt(i) == c) ++n;
+      return n;
+    };
+
+    var queryLower = query.toLowerCase();
+    var queryAlnum = (queryLower.match(/\w+/) || [''])[0];
+    var partPrefixAlnumRE = new RegExp('\\b' + queryAlnum);
+    var partExactAlnumRE = new RegExp('\\b' + queryAlnum + '\\b');
+
+    var _resultScoreFn = function(result) {
+        // scores are calculated based on exact and prefix matches,
+        // and then number of path separators (dots) from the last
+        // match (i.e. favoring classes and deep package names)
+        var score = 1.0;
+        var labelLower = result.label.toLowerCase();
+        var t;
+        t = _lastSearch(labelLower, partExactAlnumRE);
+        if (t >= 0) {
+            // exact part match
+            var partsAfter = _countChar(labelLower.substr(t + 1), '.');
+            score *= 200 / (partsAfter + 1);
+        } else {
+            t = _lastSearch(labelLower, partPrefixAlnumRE);
+            if (t >= 0) {
+                // part prefix match
+                var partsAfter = _countChar(labelLower.substr(t + 1), '.');
+                score *= 20 / (partsAfter + 1);
+            }
+        }
+
+        return score;
+    };
+
+    for (var i=0; i<gMatches.length; i++) {
+        gMatches[i].__resultScore = _resultScoreFn(gMatches[i]);
+    }
+
+    gMatches.sort(function(a,b){
+        var n = b.__resultScore - a.__resultScore;
+        if (n == 0) // lexicographical sort if scores are the same
+            n = (a.label < b.label) ? -1 : 1;
+        return n;
+    });
+}
+
+function highlight_autocomplete_result_labels(query) {
+    query = query || '';
+    if (!gMatches || !gMatches.length)
+      return;
+
+    var queryLower = query.toLowerCase();
+    var queryAlnumDot = (queryLower.match(/[\w\.]+/) || [''])[0];
+    var queryRE = new RegExp(
+        '(' + queryAlnumDot.replace(/\./g, '\\.') + ')', 'ig');
+    for (var i=0; i<gMatches.length; i++) {
+        gMatches[i].__hilabel = gMatches[i].label.replace(
+            queryRE, '<b>$1</b>');
+    }
+}
+
+function search_focus_changed(obj, focused)
+{
+    if (focused) {
+        if(obj.value == DEFAULT_TEXT){
+            obj.value = "";
+            obj.style.color="#000000";
+        }
+    } else {
+        if(obj.value == ""){
+          obj.value = DEFAULT_TEXT;
+          obj.style.color="#aaaaaa";
+        }
+        document.getElementById("search_filtered_div").className = "no-display";
+    }
+}
+
+function submit_search() {
+  var query = document.getElementById('search_autocomplete').value;
+  document.location = toRoot + 'search.html#q=' + query + '&t=0';
+  return false;
+}
diff --git a/build/tools/droiddoc/templates/assets/style.css b/build/tools/droiddoc/templates/assets/style.css
new file mode 100644 (file)
index 0000000..5ad1118
--- /dev/null
@@ -0,0 +1,316 @@
+.jd-toptitle {
+    padding-left: 6px;
+    margin-bottom: 30px;
+    font-size: 160%;
+    font-weight: bold;
+}
+
+div#jd-content table {
+    border: none;
+}
+
+div#jd-content td, div#jd-content th {
+    font-size: small;
+}
+
+div#jd-content table.jd-linktable {
+    margin-top: 3px;
+    border-spacing: 0;
+}
+
+div#jd-content p.jd-deprecated-warning {
+    margin-top: 0;
+    margin-bottom: 10px;
+}
+
+div#jd-content table.jd-linktable th {
+    vertical-align: top;
+    text-align: left;
+    padding-top: 2px;
+    padding-bottom: 2px;
+    padding-left: 7px;
+    padding-right: 7px;
+    border: none;
+    border-top: 1px solid #d2d7d0;
+    background-color: #F7FCF4;
+}
+
+div#jd-content table.jd-linktable td {
+    border: none;
+}
+
+div#jd-content table.jd-linktable td  p {
+    padding: 0;
+    margin: 0;
+    line-height: 110%;
+}
+
+div#jd-content table.jd-linktable .jd-linkcol {
+    vertical-align: top;
+    padding-top: 3px;
+    padding-bottom: 0;
+    padding-left: 7px;
+    padding-right: 7px;
+    border-top: 1px solid #d2d7d0;
+    background-color: #E5F1E0;
+    line-height: 110%;
+}
+
+div#jd-content table.jd-linktable .jd-descrcol {
+    vertical-align: top;
+    padding-top: 3px;
+    padding-bottom: 0;
+    padding-left: 7px;
+    padding-right: 7px;
+    border-top: 1px solid #d2d7d0;
+    background-color: #F7FCF4;
+    line-height: 110%;
+}
+
+div#jd-content table.jd-linktable .jd-descrcol p {
+    padding: 0;
+    margin: 0;
+    line-height: 110%;
+}
+
+div#jd-content table.jd-linktable .jd-valcol {
+    vertical-align: top;
+    padding-top: 3px;
+    padding-bottom: 0;
+    padding-left: 7px;
+    padding-right: 7px;
+    border-top: 1px solid #d2d7d0;
+    background-color: #E5F1E0;
+    line-height: 110%;
+}
+
+div#jd-content table.jd-linktable .jd-commentrow {
+    vertical-align: top;
+    padding-top: 3px;
+    padding-bottom: 4px;
+    padding-left: 7px;
+    padding-right: 7px;
+    background-color: #F7FCF4;
+    line-height: 110%;
+}
+
+div#jd-content div.jd-inheritedlinks {
+    vertical-align: top;
+    margin-top: 9px;
+    padding-left: 7px;
+    padding-right: 7px;
+    background-color: #F7FCF4;
+    line-height: 110%;
+}
+
+div#jd-content .jd-page_title-prefix {
+    padding-top: 2em;
+    margin-bottom: -14pt;
+}
+
+div#jd-content {
+    margin-left: 0;
+    margin-right: 10px;
+    margin-bottom: 0;
+}
+
+div#jd-content h1 {
+    padding-left: 10px;
+}
+
+div#jd-content h2 {
+    padding-left: 10px;
+}
+
+div#jd-content h4 {
+    margin-top: 9px;
+    margin-bottom: 1px;
+}
+
+div#jd-content .jd-descr h5 {
+    margin-bottom: 8px;
+}
+
+div#jd-content .sidebox h3 {
+    margin: 1em 0 0 0;
+}
+
+div#jd-content .jd-letterlist {
+    margin-top: 20px;
+    margin-bottom: 0;
+}
+
+div#jd-content .jd-lettertable {
+    margin-top: 15px;
+    margin-right: 10px;
+}
+div#jd-content .jd-letterentries {
+       list-style: none;
+       margin-left: 0;
+}
+div#jd-content .jd-letterentrycomments {
+    color: gray;
+}
+
+div#jd-content table.jd-inheritance-table {
+    margin-top: 0;
+    margin-left: 10px;
+    margin-right: 10px;
+    border-spacing: 0;
+}
+
+div#jd-content table.jd-inheritance-table td {
+    border: none;
+    margin: 0;
+    padding: 0;
+    background-color: white;
+}
+
+div#jd-content table.jd-inheritance-table .jd-inheritance-space {
+    width: 10px;
+}
+
+div#jd-content table.jd-inheritance-table .jd-inheritance-interface-cell {
+    padding-left: 17px;
+}
+
+div#jd-content h4.jd-details-title {
+    margin: 0;
+    background-color: #E5F1E0;
+    padding: 2px;
+    padding-left: 10px;
+    padding-right: 10px;
+    margin-top: 15px;
+}
+
+div#jd-content .jd-details {
+    margin-top: 0;
+    margin-left: -10px;
+}
+
+div#jd-content .jd-details-descr {
+    line-height: 120%;
+    padding-left: 10px;
+    padding-top: 10px;
+    padding-right: 20px;
+}
+
+div#jd-content .jd-descr h5,
+div#jd-content .jd-details h5 {
+    font-style: normal;
+    text-decoration: none;
+    font-size: 120%;
+}
+
+div#jd-content .jd-more {
+}
+
+div#jd-content .jd-descr {
+    padding-top: 0;
+}
+
+div#jd-content .jd-tagdata {
+    margin-top: 6px;
+    margin-bottom: 6px;
+}
+
+div#jd-content .jd-tagtitle {
+    margin-top: 0px;
+}
+
+div#jd-content .jd-tagtable {
+    margin-top: 10px;
+    border-spacing: 0;
+}
+
+div#jd-content .jd-tagtable th {
+    background: white;
+    padding-left: 10px;
+    padding-right: 10px;
+line-height: 120%;
+}
+
+div#jd-content .jd-tagtable th,
+div#jd-content .jd-tagtable td {
+line-height: 120%;
+    border: none;
+    margin: 0;
+    text-align: left;
+    padding-top: 0px;
+    padding-bottom: 5px;
+}
+
+div#jd-content .Code,code,pre,samp,var {
+    color: #004000;
+}
+
+div#jd-content pre.Code {
+    padding-left: 20px;
+}
+
+/* XXX I would really like to apply font-size: 9pt only if var/samp
+   is NOT inside of a .jd-descr div. */
+div#jd-content .jd-descr code,var,samp {
+    padding-left: 0px;
+}
+
+#search_autocomplete {
+    font-size: 80%;
+}
+
+div#jd-searchbox table.jd-autocomplete-table-hidden {
+    display: none;
+}
+
+div#jd-searchbox table.jd-autocomplete-table-showing {
+    z-index: 10;
+    border: 1px solid #3366cc;
+    position: relative;
+    top: -14px;
+    left: 5px;
+    background-color: white;
+}
+
+div#jd-searchbox td.jd-autocomplete {
+    font-family: Arial, sans-serif;
+    padding-left: 6px;
+    padding-right: 6px;
+    padding-top: 1px;
+    padding-bottom: 1px;
+    font-size: 80%;
+    border: none;
+    margin: 0;
+    line-height: 105%;
+}
+
+div#jd-searchbox td.jd-selected {
+    background-color: #E5F1E0;
+}
+
+div#jd-searchbox td.jd-linktype {
+    color: #999999;
+}
+
+div#jd-content .jd-expando-trigger {
+    margin-left: -8px;
+    margin-right: 0px;
+    border: none;
+}
+
+div#jd-build-id {
+    color: #666;
+    width: 100%;
+    text-align: right;
+    padding-right: 5px;
+    padding-bottom: 3px;
+}
+
+@media print {
+    #jd-searchbox, .jd-nav {
+        display: none;
+    }
+    div#jd-content {
+        margin-top: 0px;
+    }
+}
+
diff --git a/build/tools/droiddoc/templates/assets/triangle-none.gif b/build/tools/droiddoc/templates/assets/triangle-none.gif
new file mode 100644 (file)
index 0000000..0c7b469
Binary files /dev/null and b/build/tools/droiddoc/templates/assets/triangle-none.gif differ
diff --git a/build/tools/droiddoc/templates/class.cs b/build/tools/droiddoc/templates/class.cs
new file mode 100644 (file)
index 0000000..d2add18
--- /dev/null
@@ -0,0 +1,623 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<body class="<?cs var:class.since ?>">
+<?cs include:"header.cs" ?>
+
+<div class="g-unit" id="doc-content">
+
+<div id="api-info-block">
+
+<?cs # are there inherited members ?>
+<?cs each:cl=class.inherited ?>
+  <?cs if:subcount(cl.methods) ?>
+   <?cs set:inhmethods = #1 ?>
+  <?cs /if ?>
+  <?cs if:subcount(cl.constants) ?>
+   <?cs set:inhconstants = #1 ?>
+  <?cs /if ?>
+  <?cs if:subcount(cl.fields) ?>
+   <?cs set:inhfields = #1 ?>
+  <?cs /if ?>
+  <?cs if:subcount(cl.attrs) ?>
+   <?cs set:inhattrs = #1 ?>
+  <?cs /if ?>
+<?cs /each ?>
+
+<div class="sum-details-links">
+Summary:
+<?cs if:subcount(class.inners) ?>
+  <a href="#nestedclasses">Nested Classes</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:subcount(class.attrs) ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#lattrs">XML Attrs</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:inhattrs ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#inhattrs">Inherited XML Attrs</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:subcount(class.enumConstants) ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#enumconstants">Enums</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:subcount(class.constants) ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#constants">Constants</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:inhconstants ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#inhconstants">Inherited Constants</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:subcount(class.fields) ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#lfields">Fields</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:inhfields ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#inhfields">Inherited Fields</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:subcount(class.ctors.public) ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#pubctors">Ctors</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:subcount(class.ctors.protected) ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#proctors">Protected Ctors</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:subcount(class.methods.public) ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#pubmethods">Methods</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:subcount(class.methods.protected) ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#promethods">Protected Methods</a>
+  <?cs set:linkcount = #1 ?>
+<?cs /if ?>
+<?cs if:inhmethods ?>
+  <?cs if:linkcount ?>&#124; <?cs /if ?><a href="#inhmethods">Inherited Methods</a>
+<?cs /if ?>
+<?cs if:inhattrs || inhconstants || inhfields || inhmethods || subcount(class.subclasses.direct) || subcount(class.subclasses.indirect) ?>
+&#124; <a href="#" onclick="return toggleAllClassInherited()" id="toggleAllClassInherited">[Expand All]</a>
+<?cs /if ?>
+</div><!-- end sum-details-links -->
+<div class="api-level">
+  <?cs call:since_tags(class) ?>
+</div>
+</div><!-- end api-info-block -->
+
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ======== START OF CLASS DATA ======== -->
+
+<div id="jd-header">
+    <?cs var:class.scope ?>
+    <?cs var:class.static ?> 
+    <?cs var:class.final ?> 
+    <?cs var:class.abstract ?>
+    <?cs var:class.kind ?>
+<h1><?cs var:class.name ?></h1>
+
+<?cs set:colspan = subcount(class.inheritance) ?>
+<?cs each:supr = class.inheritance ?>
+  <?cs if:colspan == 2 ?>
+    extends <?cs call:type_link(supr.short_class) ?><br/>
+  <?cs /if ?>
+  <?cs if:last(supr) && subcount(supr.interfaces) ?>
+      implements 
+      <?cs each:t=supr.interfaces ?>
+        <?cs call:type_link(t) ?> 
+      <?cs /each ?>
+  <?cs /if ?>
+  <?cs set:colspan = colspan-1 ?>
+<?cs /each ?>
+
+</div><!-- end header -->
+
+<div id="naMessage"></div>
+
+<div id="jd-content" class="api apilevel-<?cs var:class.since ?>">
+<table class="jd-inheritance-table">
+<?cs set:colspan = subcount(class.inheritance) ?>
+<?cs each:supr = class.inheritance ?>
+    <tr>
+        <?cs loop:i = 1, (subcount(class.inheritance)-colspan), 1 ?>
+            <td class="jd-inheritance-space">&nbsp;<?cs if:(subcount(class.inheritance)-colspan) == i ?>&nbsp;&nbsp;&#x21b3;<?cs /if ?></td>
+        <?cs /loop ?>  
+        <td colspan="<?cs var:colspan ?>" class="jd-inheritance-class-cell"><?cs
+            if:colspan == 1
+                ?><?cs call:class_name(class.qualifiedType) ?><?cs 
+            else 
+                ?><?cs call:type_link(supr.class) ?><?cs
+            /if ?></td>
+    </tr>
+    <?cs set:colspan = colspan-1 ?>
+<?cs /each ?>
+</table>
+
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+
+<?cs if:subcount(class.subclasses.direct) ?>
+<table class="jd-sumtable jd-sumtable-subclasses"><tr><td colspan="12" style="border:none;margin:0;padding:0;">
+<?cs call:expando_trigger("subclasses-direct", "closed") ?>Known Direct Subclasses
+<?cs call:expandable_class_list("subclasses-direct", class.subclasses.direct, "list") ?>
+</td></tr></table>
+<?cs /if ?>
+
+<?cs if:subcount(class.subclasses.indirect) ?>
+<table class="jd-sumtable jd-sumtable-subclasses"><tr><td colspan="12" style="border:none;margin:0;padding:0;">
+<?cs call:expando_trigger("subclasses-indirect", "closed") ?>Known Indirect Subclasses
+<?cs call:expandable_class_list("subclasses-indirect", class.subclasses.indirect, "list") ?>
+</td></tr></table>
+<?cs /if ?>
+
+<div class="jd-descr">
+<?cs call:deprecated_warning(class) ?>
+<?cs if:subcount(class.descr) ?>
+<h2>Class Overview</h2>
+<p><?cs call:tag_list(class.descr) ?></p>
+<?cs /if ?>
+
+<?cs call:see_also_tags(class.seeAlso) ?>
+
+</div><!-- jd-descr -->
+
+
+<?cs # summary macros ?>
+
+<?cs def:write_method_summary(methods, included) ?>
+<?cs set:count = #1 ?>
+<?cs each:method = methods ?>
+        <?cs # The apilevel-N class MUST BE LAST in the sequence of class names ?>
+    <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:method.since ?>" >
+        <td class="jd-typecol"><nobr>
+            <?cs var:method.abstract ?>
+            <?cs var:method.synchronized ?>
+            <?cs var:method.final ?>
+            <?cs var:method.static ?>
+            <?cs call:type_link(method.generic) ?>
+            <?cs call:type_link(method.returnType) ?></nobr>
+        </td>
+        <td class="jd-linkcol" width="100%"><nobr>
+        <span class="sympad"><?cs call:cond_link(method.name, toroot, method.href, included) ?></span>(<?cs call:parameter_list(method.params) ?>)</nobr>
+        <?cs if:subcount(method.shortDescr) || subcount(method.deprecated) ?>
+        <div class="jd-descrdiv"><?cs call:short_descr(method) ?></div>
+  <?cs /if ?>
+  </td></tr>
+<?cs set:count = count + #1 ?>
+<?cs /each ?>
+<?cs /def ?>
+
+<?cs def:write_field_summary(fields, included) ?>
+<?cs set:count = #1 ?>
+    <?cs each:field=fields ?>
+      <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:field.since ?>" >
+          <td class="jd-typecol"><nobr>
+          <?cs var:field.scope ?>
+          <?cs var:field.static ?>
+          <?cs var:field.final ?>
+          <?cs call:type_link(field.type) ?></nobr></td>
+          <td class="jd-linkcol"><?cs call:cond_link(field.name, toroot, field.href, included) ?></td>
+          <td class="jd-descrcol" width="100%"><?cs call:short_descr(field) ?></td>
+      </tr>
+      <?cs set:count = count + #1 ?>
+    <?cs /each ?>
+<?cs /def ?>
+
+<?cs def:write_constant_summary(fields, included) ?>
+<?cs set:count = #1 ?>
+    <?cs each:field=fields ?>
+    <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:field.since ?>" >
+        <td class="jd-typecol"><?cs call:type_link(field.type) ?></td>
+        <td class="jd-linkcol"><?cs call:cond_link(field.name, toroot, field.href, included) ?></td>
+        <td class="jd-descrcol" width="100%"><?cs call:short_descr(field) ?></td>
+    </tr>
+    <?cs set:count = count + #1 ?>
+    <?cs /each ?>
+<?cs /def ?>
+
+<?cs def:write_attr_summary(attrs, included) ?>
+<?cs set:count = #1 ?>
+    <tr>
+        <td><nobr><em>Attribute Name</em></nobr></td>
+        <td><nobr><em>Related Method</em></nobr></td>
+        <td><nobr><em>Description</em></nobr></td>
+    </tr>
+    <?cs each:attr=attrs ?>
+    <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:attr.since ?>" >
+        <td class="jd-linkcol"><?cs if:included ?><a href="<?cs var:toroot ?><?cs var:attr.href ?>"><?cs /if ?><?cs var:attr.name ?><?cs if:included ?></a><?cs /if ?></td>
+        <td class="jd-linkcol"><?cs each:m=attr.methods ?>
+            <?cs call:cond_link(m.name, toroot, m.href, included) ?>
+            <?cs /each ?>
+        </td>
+        <td class="jd-descrcol" width="100%"><?cs call:short_descr(attr) ?>&nbsp;</td>
+    </tr>
+    <?cs set:count = count + #1 ?>
+    <?cs /each ?>
+<?cs /def ?>
+
+<?cs def:write_inners_summary(classes) ?>
+<?cs set:count = #1 ?>
+  <?cs each:cl=class.inners ?>
+    <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:cl.since ?>" >
+      <td class="jd-typecol"><nobr>
+        <?cs var:cl.scope ?>
+        <?cs var:cl.static ?> 
+        <?cs var:cl.final ?> 
+        <?cs var:cl.abstract ?>
+        <?cs var:cl.kind ?></nobr></td>
+      <td class="jd-linkcol"><?cs call:type_link(cl.type) ?></td>
+      <td class="jd-descrcol" width="100%"><?cs call:short_descr(cl) ?>&nbsp;</td>
+    </tr>
+    <?cs set:count = count + #1 ?>
+    <?cs /each ?>
+<?cs /def ?>
+
+<?cs # end macros ?>
+
+<div class="jd-descr">
+<h2>Summary</h2>
+
+<?cs if:subcount(class.inners) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ======== NESTED CLASS SUMMARY ======== -->
+<table id="nestedclasses" class="jd-sumtable"><tr><th colspan="12">Nested Classes</th></tr>
+<?cs call:write_inners_summary(class.inners) ?>
+<?cs /if ?>
+
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<?cs if:subcount(class.attrs) ?>
+<!-- =========== FIELD SUMMARY =========== -->
+<table id="lattrs" class="jd-sumtable"><tr><th colspan="12">XML Attributes</th></tr>
+<?cs call:write_attr_summary(class.attrs, 1) ?>
+<?cs /if ?>
+
+<?cs # if there are inherited attrs, write the table ?>
+<?cs if:inhattrs ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- =========== FIELD SUMMARY =========== -->
+<table id="inhattrs" class="jd-sumtable"><tr><th>
+  <a href="#" class="toggle-all" onclick="return toggleAllInherited(this, null)">[Expand]</a>
+  <div style="clear:left;">Inherited XML Attributes</div></th></tr>
+<?cs each:cl=class.inherited ?>
+<?cs if:subcount(cl.attrs) ?>
+<tr class="api apilevel-<?cs var:cl.since ?>" >
+<td colspan="12">
+<?cs call:expando_trigger("inherited-attrs-"+cl.qualified, "closed") ?>From <?cs var:cl.kind ?>
+<?cs call:cond_link(cl.qualified, toroot, cl.link, cl.included) ?>
+<div id="inherited-attrs-<?cs var:cl.qualified ?>">
+  <div id="inherited-attrs-<?cs var:cl.qualified ?>-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-attrs-<?cs var:cl.qualified ?>-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    <?cs call:write_attr_summary(cl.attrs, cl.included) ?></table>
+  </div>
+</div>
+</td></tr>
+<?cs /if ?>
+<?cs /each ?>
+</table>
+<?cs /if ?>
+
+<?cs if:subcount(class.enumConstants) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- =========== ENUM CONSTANT SUMMARY =========== -->
+<table id="enumconstants" class="jd-sumtable"><tr><th colspan="12">Enum Values</th></tr>
+<?cs set:count = #1 ?>
+    <?cs each:field=class.enumConstants ?>
+    <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:field.since ?>" >
+        <td class="jd-descrcol"><?cs call:type_link(field.type) ?>&nbsp;</td>
+        <td class="jd-linkcol"><?cs call:cond_link(field.name, toroot, field.href, cl.included) ?>&nbsp;</td>
+        <td class="jd-descrcol" width="100%"><?cs call:short_descr(field) ?>&nbsp;</td>
+    </tr>
+    <?cs set:count = count + #1 ?>
+    <?cs /each ?>
+<?cs /if ?>
+
+<?cs if:subcount(class.constants) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- =========== ENUM CONSTANT SUMMARY =========== -->
+<table id="constants" class="jd-sumtable"><tr><th colspan="12">Constants</th></tr>
+<?cs call:write_constant_summary(class.constants, 1) ?>
+</table>
+<?cs /if ?>
+
+<?cs # if there are inherited constants, write the table ?>
+<?cs if:inhconstants ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- =========== ENUM CONSTANT SUMMARY =========== -->
+<table id="inhconstants" class="jd-sumtable"><tr><th>
+  <a href="#" class="toggle-all" onclick="return toggleAllInherited(this, null)">[Expand]</a>
+  <div style="clear:left;">Inherited Constants</div></th></tr>
+<?cs each:cl=class.inherited ?>
+<?cs if:subcount(cl.constants) ?>
+<tr class="api apilevel-<?cs var:cl.since ?>" >
+<td colspan="12">
+<?cs call:expando_trigger("inherited-constants-"+cl.qualified, "closed") ?>From <?cs var:cl.kind ?>
+<?cs call:cond_link(cl.qualified, toroot, cl.link, cl.included) ?>
+<div id="inherited-constants-<?cs var:cl.qualified ?>">
+  <div id="inherited-constants-<?cs var:cl.qualified ?>-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-constants-<?cs var:cl.qualified ?>-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    <?cs call:write_constant_summary(cl.constants, cl.included) ?></table>
+  </div>
+</div>
+</td></tr>
+<?cs /if ?>
+<?cs /each ?>
+</table>
+<?cs /if ?>
+
+<?cs if:subcount(class.fields) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- =========== FIELD SUMMARY =========== -->
+<table id="lfields" class="jd-sumtable"><tr><th colspan="12">Fields</th></tr>
+<?cs call:write_field_summary(class.fields, 1) ?>
+</table>
+<?cs /if ?>
+
+<?cs # if there are inherited fields, write the table ?>
+<?cs if:inhfields ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- =========== FIELD SUMMARY =========== -->
+<table id="inhfields" class="jd-sumtable"><tr><th>
+  <a href="#" class="toggle-all" onclick="return toggleAllInherited(this, null)">[Expand]</a>
+  <div style="clear:left;">Inherited Fields</div></th></tr>
+<?cs each:cl=class.inherited ?>
+<?cs if:subcount(cl.fields) ?>
+<tr class="api apilevel-<?cs var:cl.since ?>" >
+<td colspan="12">
+<?cs call:expando_trigger("inherited-fields-"+cl.qualified, "closed") ?>From <?cs var:cl.kind ?>
+<?cs call:cond_link(cl.qualified, toroot, cl.link, cl.included) ?>
+<div id="inherited-fields-<?cs var:cl.qualified ?>">
+  <div id="inherited-fields-<?cs var:cl.qualified ?>-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-fields-<?cs var:cl.qualified ?>-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    <?cs call:write_field_summary(cl.fields, cl.included) ?></table>
+  </div>
+</div>
+</td></tr>
+<?cs /if ?>
+<?cs /each ?>
+</table>
+<?cs /if ?>
+
+<?cs if:subcount(class.ctors.public) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+<table id="pubctors" class="jd-sumtable"><tr><th colspan="12">Public Constructors</th></tr>
+<?cs call:write_method_summary(class.ctors.public, 1) ?>
+</table>
+<?cs /if ?>
+
+<?cs if:subcount(class.ctors.protected) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+<table id="proctors" class="jd-sumtable"><tr><th colspan="12">Protected Constructors</th></tr>
+<?cs call:write_method_summary(class.ctors.protected, 1) ?>
+</table>
+<?cs /if ?>
+
+<?cs if:subcount(class.methods.public) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========== METHOD SUMMARY =========== -->
+<table id="pubmethods" class="jd-sumtable"><tr><th colspan="12">Public Methods</th></tr>
+<?cs call:write_method_summary(class.methods.public, 1) ?>
+</table>
+<?cs /if ?>
+
+<?cs if:subcount(class.methods.protected) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========== METHOD SUMMARY =========== -->
+<table id="promethods" class="jd-sumtable"><tr><th colspan="12">Protected Methods</th></tr>
+<?cs call:write_method_summary(class.methods.protected, 1) ?>
+</table>
+<?cs /if ?>
+
+<?cs # if there are inherited methods, write the table ?>
+<?cs if:inhmethods ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========== METHOD SUMMARY =========== -->
+<table id="inhmethods" class="jd-sumtable"><tr><th>
+  <a href="#" class="toggle-all" onclick="return toggleAllInherited(this, null)">[Expand]</a>
+  <div style="clear:left;">Inherited Methods</div></th></tr>
+<?cs each:cl=class.inherited ?>
+<?cs if:subcount(cl.methods) ?>
+<tr class="api apilevel-<?cs var:cl.since ?>" >
+<td colspan="12"><?cs call:expando_trigger("inherited-methods-"+cl.qualified, "closed") ?>
+From <?cs var:cl.kind ?> <?cs call:cond_link(cl.qualified, toroot, cl.link, cl.included) ?>
+<div id="inherited-methods-<?cs var:cl.qualified ?>">
+  <div id="inherited-methods-<?cs var:cl.qualified ?>-list"
+        class="jd-inheritedlinks">
+  </div>
+  <div id="inherited-methods-<?cs var:cl.qualified ?>-summary" style="display: none;">
+    <table class="jd-sumtable-expando">
+    <?cs call:write_method_summary(cl.methods, cl.included) ?></table>
+  </div>
+</div>
+</td></tr>
+<?cs /if ?>
+<?cs /each ?>
+</table>
+<?cs /if ?>
+
+</div><!-- jd-descr (summary) -->
+
+<!-- Details -->
+
+<?cs def:write_field_details(fields) ?>
+<?cs each:field=fields ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<?cs # the A tag in the next line must remain where it is, so that Eclipse can parse the docs ?>
+<A NAME="<?cs var:field.anchor ?>"></A>
+<?cs # The apilevel-N class MUST BE LAST in the sequence of class names ?>
+<div class="jd-details api apilevel-<?cs var:field.since ?>"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        <?cs var:field.scope ?> 
+        <?cs var:field.static ?> 
+        <?cs var:field.final ?> 
+        <?cs call:type_link(field.type) ?>
+      </span>
+        <?cs var:field.name ?>
+    </h4>
+      <div class="api-level">
+        <?cs call:since_tags(field) ?>
+      </div>
+    <div class="jd-details-descr">
+      <?cs call:description(field) ?>
+    <?cs if:subcount(field.constantValue) ?>
+        <div class="jd-tagdata">
+        <span class="jd-tagtitle">Constant Value: </span>
+        <span>
+            <?cs if:field.constantValue.isString ?>
+                <?cs var:field.constantValue.str ?>
+            <?cs else ?>
+                <?cs var:field.constantValue.dec ?>
+                (<?cs var:field.constantValue.hex ?>)
+            <?cs /if ?>
+        </span>
+        </div>
+    <?cs /if ?>
+    </div>
+</div>
+<?cs /each ?>
+<?cs /def ?>
+
+<?cs def:write_method_details(methods) ?>
+<?cs each:method=methods ?>
+<?cs # the A tag in the next line must remain where it is, so that Eclipse can parse the docs ?>
+<A NAME="<?cs var:method.anchor ?>"></A>
+<?cs # The apilevel-N class MUST BE LAST in the sequence of class names ?>
+<div class="jd-details api apilevel-<?cs var:method.since ?>"> 
+    <h4 class="jd-details-title">
+      <span class="normal">
+        <?cs var:method.scope ?> 
+        <?cs var:method.static ?> 
+        <?cs var:method.final ?> 
+        <?cs var:method.abstract ?> 
+        <?cs var:method.synchronized ?> 
+        <?cs call:type_link(method.returnType) ?>
+      </span>
+      <span class="sympad"><?cs var:method.name ?></span>
+      <span class="normal">(<?cs call:parameter_list(method.params) ?>)</span>
+    </h4>
+      <div class="api-level">
+        <?cs call:since_tags(method) ?>
+      </div>
+    <div class="jd-details-descr">
+      <?cs call:description(method) ?>
+    </div>
+</div>
+<?cs /each ?>
+<?cs /def ?>
+
+<?cs def:write_attr_details(attrs) ?>
+<?cs each:attr=attrs ?>
+<?cs # the A tag in the next line must remain where it is, so that Eclipse can parse the docs ?>
+<A NAME="<?cs var:attr.anchor ?>"></A>
+<?cs # The apilevel-N class MUST BE LAST in the sequence of class names ?>
+<div class="jd-details api apilevel-<?cs var:attr.since ?>"> 
+    <h4 class="jd-details-title"><?cs var:attr.name ?>
+    </h4>
+      <div class="api-level">
+        <?cs call:since_tags(attr) ?>
+      </div>
+    <div class="jd-details-descr">
+        <?cs call:description(attr) ?>
+
+        <div class="jd-tagdata">
+            <h5 class="jd-tagtitle">Related Methods</h5>
+            <ul class="nolist">
+            <?cs each:m=attr.methods ?>
+                <li><a href="<?cs var:toroot ?><?cs var:m.href ?>"><?cs var:m.name ?></a></li>
+            <?cs /each ?>
+            </ul>
+        </div>
+    </div>
+</div>
+<?cs /each ?>
+<?cs /def ?>
+
+
+<!-- XML Attributes -->
+<?cs if:subcount(class.attrs) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========= FIELD DETAIL ======== -->
+<h2>XML Attributes</h2>
+<?cs call:write_attr_details(class.attrs) ?>
+<?cs /if ?>
+
+<!-- Enum Values -->
+<?cs if:subcount(class.enumConstants) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========= ENUM CONSTANTS DETAIL ======== -->
+<h2>Enum Values</h2>
+<?cs call:write_field_details(class.enumConstants) ?>
+<?cs /if ?>
+
+<!-- Constants -->
+<?cs if:subcount(class.constants) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========= ENUM CONSTANTS DETAIL ======== -->
+<h2>Constants</h2>
+<?cs call:write_field_details(class.constants) ?>
+<?cs /if ?>
+
+<!-- Fields -->
+<?cs if:subcount(class.fields) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========= FIELD DETAIL ======== -->
+<h2>Fields</h2>
+<?cs call:write_field_details(class.fields) ?>
+<?cs /if ?>
+
+<!-- Public ctors -->
+<?cs if:subcount(class.ctors.public) ?>
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+<h2>Public Constructors</h2>
+<?cs call:write_method_details(class.ctors.public) ?>
+<?cs /if ?>
+
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+<!-- Protected ctors -->
+<?cs if:subcount(class.ctors.protected) ?>
+<h2>Protected Constructors</h2>
+<?cs call:write_method_details(class.ctors.protected) ?>
+<?cs /if ?>
+
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========= METHOD DETAIL ======== -->
+<!-- Public methdos -->
+<?cs if:subcount(class.methods.public) ?>
+<h2>Public Methods</h2>
+<?cs call:write_method_details(class.methods.public) ?>
+<?cs /if ?>
+
+<?cs # this next line must be exactly like this to be parsed by eclipse ?>
+<!-- ========= METHOD DETAIL ======== -->
+<?cs if:subcount(class.methods.protected) ?>
+<h2>Protected Methods</h2>
+<?cs call:write_method_details(class.methods.protected) ?>
+<?cs /if ?>
+
+<?cs # the next two lines must be exactly like this to be parsed by eclipse ?>
+<!-- ========= END OF CLASS DATA ========= -->
+<A NAME="navbar_top"></A>
+
+<?cs include:"footer.cs" ?>
+</div> <!-- jd-content -->
+
+</div><!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
diff --git a/build/tools/droiddoc/templates/classes.cs b/build/tools/droiddoc/templates/classes.cs
new file mode 100644 (file)
index 0000000..5a8315f
--- /dev/null
@@ -0,0 +1,41 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<?cs include:"header.cs" ?>
+
+<div class="g-unit" id="doc-content">
+
+<div id="jd-header">
+<h1><?cs var:page.title ?></h1>
+</div>
+
+<div id="jd-content">
+
+<div class="jd-letterlist"><?cs each:letter=docs.classes ?>
+    <a href="#letter_<?cs name:letter ?>"><?cs name:letter ?></a><?cs /each?>
+</div>
+
+<?cs each:letter=docs.classes ?>
+<?cs set:count = #1 ?>
+<h2 id="letter_<?cs name:letter ?>"><?cs name:letter ?></h2>
+<table class="jd-sumtable">
+    <?cs set:cur_row = #0 ?>
+    <?cs each:cl = letter ?>
+        <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:cl.since ?>" >
+            <td class="jd-linkcol"><?cs call:type_link(cl.type) ?></td>
+            <td class="jd-descrcol" width="100%"><?cs call:short_descr(cl) ?>&nbsp;</td>
+        </tr>
+    <?cs set:count = count + #1 ?>
+    <?cs /each ?>
+</table>
+<?cs /each ?>
+
+<?cs include:"footer.cs" ?>
+</div><!-- end jd-content -->
+</div><!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/build/tools/droiddoc/templates/customization.cs b/build/tools/droiddoc/templates/customization.cs
new file mode 100644 (file)
index 0000000..f6a5c1a
--- /dev/null
@@ -0,0 +1,31 @@
+<?cs # This default template file is meant to be replaced.                      ?>
+<?cs # Use the -templatedir arg to javadoc to set your own directory with a     ?>
+<?cs # replacement for this file in it. ?>
+
+
+<?cs def:default_search_box() ?><?cs /def ?>
+<?cs def:default_left_nav() ?><?cs /def ?>
+
+<?cs # appears at the top of every page ?><?cs 
+def:custom_masthead() ?>
+  <div id="header">
+      <div id="headerLeft">
+          <a href="<?cs var:toroot ?>index.html" tabindex="-1"><?cs var:page.title ?></a>
+      </div>
+      <div id="headerRight">
+          <?cs if:!online-pdk ?>
+            <?cs call:default_search_box() ?>
+          <?cs /if ?>
+      </div><!-- headerRight -->
+  </div><!-- header --><?cs 
+/def ?>
+
+<?cs # appear at the bottom of every page ?>
+<?cs def:custom_copyright() ?><?cs /def ?>
+<?cs def:custom_cc_copyright() ?><?cs /def ?>
+<?cs def:custom_footerlinks() ?><?cs /def ?>
+<?cs def:custom_buildinfo() ?>Build <?cs var:page.build ?> - <?cs var:page.now ?><?cs /def ?>
+
+<?cs # appears on the side of the page ?>
+<?cs def:custom_left_nav() ?><?cs call:default_left_nav() ?><?cs /def ?>
+
diff --git a/build/tools/droiddoc/templates/docpage.cs b/build/tools/droiddoc/templates/docpage.cs
new file mode 100644 (file)
index 0000000..9d85c6f
--- /dev/null
@@ -0,0 +1,41 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<body class="gc-documentation">
+<?cs include:"header.cs" ?>
+
+<div class="g-unit" id="doc-content"><a name="top"></a>
+
+<div id="jd-header" class="guide-header">
+  <span class="crumb">
+    <?cs if:parent.link ?>
+      <a href="<?cs var:parent.link ?>"><?cs var:parent.title ?></a> >
+    <?cs else ?>&nbsp;
+    <?cs /if ?>
+  </span>
+<h1><?cs var:page.title ?></h1>
+</div>
+
+  <div id="jd-content">
+
+    <div class="jd-descr">
+    <?cs call:tag_list(root.descr) ?>
+    </div>
+
+  <a href="#top" style="float:right">&uarr; Go to top</a>
+  <?cs if:parent.link ?>
+    <p><a href="<?cs var:parent.link ?>">&larr; Back to <?cs var:parent.title ?></a></p>
+  <?cs /if ?>
+  </div>
+
+<?cs include:"footer.cs" ?>
+</div><!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
+
+
+
diff --git a/build/tools/droiddoc/templates/doctype.cs b/build/tools/droiddoc/templates/doctype.cs
new file mode 100644 (file)
index 0000000..763b073
--- /dev/null
@@ -0,0 +1 @@
+<!DOCTYPE html>
\ No newline at end of file
diff --git a/build/tools/droiddoc/templates/footer.cs b/build/tools/droiddoc/templates/footer.cs
new file mode 100644 (file)
index 0000000..bb82c8d
--- /dev/null
@@ -0,0 +1,19 @@
+<div id="footer">
+
+<?cs if:reference||guide ?>
+  <div id="copyright">
+    <?cs call:custom_copyright() ?>
+  </div>
+  <div id="build_info">
+    <?cs call:custom_buildinfo() ?>
+  </div>
+<?cs elif:!hide_license_footer ?>
+  <div id="copyright">
+    <?cs call:custom_cc_copyright() ?>
+  </div>
+<?cs /if ?>
+  <div id="footerlinks">
+    <?cs call:custom_footerlinks() ?>
+  </div>
+
+</div> <!-- end footer -->
diff --git a/build/tools/droiddoc/templates/head_tag.cs b/build/tools/droiddoc/templates/head_tag.cs
new file mode 100644 (file)
index 0000000..5a7fd40
--- /dev/null
@@ -0,0 +1,34 @@
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link rel="shortcut icon" type="image/x-icon" href="<?cs var:toroot ?>favicon.ico" />
+<title><?cs 
+  if:page.title ?><?cs 
+    var:page.title ?> | <?cs
+  /if ?>Android Developers</title><?cs 
+if:guide||sdk||resources ?>
+<link href="<?cs var:toroot ?>assets/android-developer-docs-devguide.css" rel="stylesheet" type="text/css" /><?cs 
+else ?>
+<link href="<?cs var:toroot ?>assets/android-developer-docs.css" rel="stylesheet" type="text/css" /><?cs 
+/if ?>
+<script src="<?cs var:toroot ?>assets/search_autocomplete.js" type="text/javascript"></script>
+<script src="<?cs var:toroot ?>assets/jquery-resizable.min.js" type="text/javascript"></script>
+<script src="<?cs var:toroot ?>assets/android-developer-docs.js" type="text/javascript"></script>
+<script src="<?cs var:toroot ?>assets/prettify.js" type="text/javascript"></script>
+<script type="text/javascript">
+  setToRoot("<?cs var:toroot ?>");
+</script><?cs 
+if:reference ?>
+<script src="<?cs var:toroot ?>assets/android-developer-reference.js" type="text/javascript"></script>
+<script src="<?cs var:toroot ?>navtree_data.js" type="text/javascript"></script><?cs 
+/if ?>
+<noscript>
+  <style type="text/css">
+    html,body{overflow:auto;}
+    #body-content{position:relative; top:0;}
+    #doc-content{overflow:visible;border-left:3px solid #666;}
+    #side-nav{padding:0;}
+    #side-nav .toggle-list ul {display:block;}
+    #resize-packages-nav{border-bottom:3px solid #666;}
+  </style>
+</noscript>
+</head>
diff --git a/build/tools/droiddoc/templates/header.cs b/build/tools/droiddoc/templates/header.cs
new file mode 100644 (file)
index 0000000..e8301be
--- /dev/null
@@ -0,0 +1,3 @@
+<?cs call:custom_masthead() ?>
+<?cs call:custom_left_nav() ?>
+
diff --git a/build/tools/droiddoc/templates/hierarchy.cs b/build/tools/droiddoc/templates/hierarchy.cs
new file mode 100644 (file)
index 0000000..a607ffd
--- /dev/null
@@ -0,0 +1,68 @@
+<?cs include:"macros.cs" ?>
+<html>
+<style>
+    .jd-hierarchy-spacer {
+        width: 15px;
+    }
+    .jd-hierarchy-data {
+        text-align: left;
+        vertical-align: top;
+    }
+</style>
+<?cs include:"head_tag.cs" ?>
+<?cs include:"header.cs" ?>
+
+<div class="g-unit" id="doc-content">
+
+<div id="jd-header">
+<h1><?cs var:page.title ?></h1>
+</div>
+
+<div id="jd-content">
+
+<div style="margin-left: 20px; margin-right: 20px;">
+
+<?cs def:hierarchy_list(classes) ?>
+<?cs each:cl = classes ?>
+<tr>
+    <?cs loop:x=#0,cl.indent,#1 ?><td class="jd-hierarchy-spacer"></td><?cs /loop ?>
+    <td class="jd-hierarchy-data" colspan="<?cs var:cl.colspan ?>">
+    <?cs if:cl.exists ?>
+        <?cs call:type_link(cl.class) ?>
+    <?cs else ?>
+        <?cs var:cl.value ?>
+    <?cs /if ?>
+    </td>
+    <td class="jd-hierarchy-data">
+    <?cs each:iface = cl.interfaces ?>
+        <?cs if:iface.exists ?>
+            <?cs call:type_link(iface.class) ?>
+        <?cs else ?>
+            <?cs var:iface.value ?>
+        <?cs /if ?> &nbsp;&nbsp;
+    <?cs /each ?>
+    &nbsp;
+    </td>
+</tr>
+<?cs call:hierarchy_list(cl.derived) ?>
+<?cs /each ?>
+<?cs /def ?>
+
+
+<table border="0" cellpadding="0" cellspacing="1">
+<th class="jd-hierarchy-data" colspan="<?cs var:colspan ?>">Class</th>
+<th class="jd-hierarchy-data">Interfaces</th>
+<?cs call:hierarchy_list(classes) ?>
+</table>
+
+</div>
+
+<?cs include:"footer.cs" ?>
+</div><!-- end jd-content -->
+</div><!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
+
diff --git a/build/tools/droiddoc/templates/index.cs b/build/tools/droiddoc/templates/index.cs
new file mode 100644 (file)
index 0000000..15a6a59
--- /dev/null
@@ -0,0 +1,8 @@
+<html>
+<head>
+<meta http-equiv="refresh" content="0;url=packages.html">
+</head>
+<body>
+<?cs include:"analytics.cs" ?>
+</body>
+</html>
\ No newline at end of file
diff --git a/build/tools/droiddoc/templates/keywords.cs b/build/tools/droiddoc/templates/keywords.cs
new file mode 100644 (file)
index 0000000..0c8d4e3
--- /dev/null
@@ -0,0 +1,37 @@
+<?cs include:"macros.cs" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<?cs include:"header.cs" ?>
+
+<div class="g-unit" id="doc-content">
+
+<div id="jd-header">
+<h1><?cs var:page.title ?></h1>
+</div>
+
+<div id="jd-content">
+
+<div class="jd-letterlist"><?cs each:letter=keywords ?>
+    <a href="#letter_<?cs name:letter ?>"><?cs name:letter ?></a><?cs /each?>
+</div>
+
+<?cs each:letter=keywords ?>
+<a name="letter_<?cs name:letter ?>"></a>
+<h2><?cs name:letter ?></h2>
+<ul class="jd-letterentries">
+<?cs each:entry=letter
+?>  <li><a href="<?cs var:toroot ?><?cs var:entry.href ?>"><?cs var:entry.label
+        ?></a>&nbsp;<font class="jd-letterentrycomments">(<?cs var:entry.comment ?>)</font></li>
+<?cs /each
+?></ul>
+
+<?cs /each ?>
+
+<?cs include:"footer.cs" ?>
+</div><!-- end jd-content -->
+</div><!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
diff --git a/build/tools/droiddoc/templates/lists.cs b/build/tools/droiddoc/templates/lists.cs
new file mode 100644 (file)
index 0000000..0af32b2
--- /dev/null
@@ -0,0 +1,5 @@
+var DATA = [
+<?cs each:page = docs.pages
+?>      { id:<?cs var: page.id ?>, label:"<?cs var:page.label ?>", link:"<?cs var:page.link ?>", type:"<?cs var:page.type ?>" }<?cs if:!last(page) ?>,<?cs /if ?>
+<?cs /each ?>
+    ];
diff --git a/build/tools/droiddoc/templates/macros.cs b/build/tools/droiddoc/templates/macros.cs
new file mode 100644 (file)
index 0000000..b5fd3f2
--- /dev/null
@@ -0,0 +1,266 @@
+<?cs # A link to a package ?><?cs 
+def:package_link(pkg)) ?>
+  <a href="<?cs var:toroot ?><?cs var:pkg.link ?>"><?cs var:pkg.name ?></a><?cs 
+/def ?>
+
+<?cs # A link to a type, or not if it's a primitive type
+        link: whether to create a link at the top level, always creates links in
+              recursive invocations.
+        Expects the following fields:
+            .name
+            .link
+            .isPrimitive
+            .superBounds.N.(more links)   (... super ... & ...)
+            .extendsBounds.N.(more links) (... extends ... & ...)
+            .typeArguments.N.(more links) (< ... >)
+?><?cs 
+def:type_link_impl(type, link) ?><?cs
+  if:type.link && link=="true" ?><a href="<?cs var:toroot ?><?cs var:type.link ?>"><?cs /if
+      ?><?cs var:type.label ?><?cs if:type.link && link=="true" ?></a><?cs /if ?><?cs
+  if:subcount(type.extendsBounds) ?><?cs
+      each:t=type.extendsBounds ?><?cs
+          if:first(t) ?>&nbsp;extends&nbsp;<?cs else ?>&nbsp;&amp;&nbsp;<?cs /if ?><?cs
+          call:type_link_impl(t, "true") ?><?cs
+      /each ?><?cs
+  /if ?><?cs
+  if:subcount(type.superBounds) ?><?cs
+      each:t=type.superBounds ?><?cs
+          if:first(t) ?>&nbsp;super&nbsp;<?cs else ?>&nbsp;&amp;&nbsp;<?cs /if ?><?cs
+          call:type_link_impl(t, "true") ?><?cs
+      /each ?><?cs
+  /if ?><?cs
+  if:subcount(type.typeArguments)
+      ?>&lt;<?cs each:t=type.typeArguments ?><?cs call:type_link_impl(t, "true") ?><?cs
+          if:!last(t) ?>,&nbsp;<?cs /if ?><?cs
+      /each ?>&gt;<?cs
+  /if ?><?cs
+/def ?>
+
+<?cs def:class_name(type) ?><?cs call:type_link_impl(type, "false") ?><?cs /def ?>
+<?cs def:type_link(type) ?><?cs call:type_link_impl(type, "true") ?><?cs /def ?>
+
+<?cs # a conditional link.
+      if the "condition" parameter evals to true then the link is displayed
+      otherwise only the text is displayed
+?><?cs
+def:cond_link(text, root, path, condition) ?><?cs
+  if:condition ?><a href="<?cs var:root ?><?cs var:path ?>"><?cs /if ?><?cs var:text ?><?cs if:condition ?></a><?cs /if ?><?cs
+/def ?>
+
+
+<?cs # A comma separated parameter list ?><?cs 
+def:parameter_list(params) ?><?cs
+  each:param = params ?><?cs
+      call:type_link(param.type)?> <?cs
+      var:param.name ?><?cs
+      if: name(param)!=subcount(params)-1?>, <?cs /if ?><?cs
+  /each ?><?cs
+/def ?>
+
+<?cs # Print a list of tags (e.g. description text ?><?cs 
+def:tag_list(tags) ?><?cs
+  each:tag = tags ?><?cs
+      if:tag.name == "Text" ?><?cs var:tag.text?><?cs
+      elif:tag.kind == "@more" ?><p><?cs
+      elif:tag.kind == "@see" ?><code><a href="<?cs var:toroot ?><?cs var:tag.href ?>"><?cs var:tag.label ?></a></code><?cs
+      elif:tag.kind == "@seeHref" ?><a href="<?cs var:tag.href ?>"><?cs var:tag.label ?></a><?cs
+      elif:tag.kind == "@seeJustLabel" ?><?cs var:tag.label ?><?cs
+      elif:tag.kind == "@code" ?><code><?cs var:tag.text ?></code><?cs
+      elif:tag.kind == "@samplecode" ?><pre><?cs var:tag.text ?></pre><?cs
+      elif:tag.name == "@sample" ?><pre><?cs var:tag.text ?></pre><?cs
+      elif:tag.name == "@include" ?><?cs var:tag.text ?><?cs
+      elif:tag.kind == "@docRoot" ?><?cs var:toroot ?><?cs
+      elif:tag.kind == "@sdkCurrent" ?><?cs var:sdk.current ?><?cs
+      elif:tag.kind == "@sdkCurrentVersion" ?><?cs var:sdk.version ?><?cs
+      elif:tag.kind == "@sdkCurrentRelId" ?><?cs var:sdk.rel.id ?><?cs
+      elif:tag.kind == "@sdkPlatformVersion" ?><?cs var:sdk.platform.version ?><?cs
+      elif:tag.kind == "@sdkPlatformApiLevel" ?><?cs var:sdk.platform.apiLevel ?><?cs
+      elif:tag.kind == "@sdkPlatformMajorMinor" ?><?cs var:sdk.platform.majorMinor ?><?cs
+      elif:tag.kind == "@sdkPlatformReleaseDate" ?><?cs var:sdk.platform.releaseDate ?><?cs
+      elif:tag.kind == "@sdkPlatformDeployableDate" ?><?cs var:sdk.platform.deployableDate ?><?cs
+      elif:tag.kind == "@adtZipVersion" ?><?cs var:adt.zip.version ?><?cs
+      elif:tag.kind == "@adtZipDownload" ?><?cs var:adt.zip.download ?><?cs
+      elif:tag.kind == "@adtZipBytes" ?><?cs var:adt.zip.bytes ?><?cs
+      elif:tag.kind == "@adtZipChecksum" ?><?cs var:adt.zip.checksum ?><?cs
+      elif:tag.kind == "@inheritDoc" ?><?cs # This is the case when @inheritDoc is in something
+                                              that doesn't inherit from anything?><?cs
+      elif:tag.kind == "@attr" ?><?cs
+      else ?>{<?cs var:tag.name?> <?cs var:tag.text ?>}<?cs
+      /if ?><?cs
+  /each ?><?cs
+/def ?>
+
+<?cs # The message about This xxx is deprecated. ?><?cs 
+def:deprecated_text(kind) ?>
+  This <?cs var:kind ?> is deprecated.<?cs 
+/def ?>
+
+<?cs # Show the short-form description of something.  These come from shortDescr and deprecated ?><?cs 
+def:short_descr(obj) ?><?cs
+  if:subcount(obj.deprecated) ?>
+      <em><?cs call:deprecated_text(obj.kind) ?>
+      <?cs call:tag_list(obj.deprecated) ?></em><?cs
+  else ?><?cs call:tag_list(obj.shortDescr) ?><?cs
+  /if ?><?cs
+/def ?>
+
+<?cs # Show the red box with the deprecated warning ?><?cs 
+def:deprecated_warning(obj) ?><?cs 
+  if:subcount(obj.deprecated) ?><p>
+  <p class="caution">
+      <strong><?cs call:deprecated_text(obj.kind) ?></strong><br/> <?cs 
+      call:tag_list(obj.deprecated) ?>
+  </p><?cs 
+  /if ?><?cs 
+/def ?>
+
+<?cs # print the See Also: section ?><?cs 
+def:see_also_tags(also) ?><?cs 
+  if:subcount(also) ?>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">See Also</h5>
+      <ul class="nolist"><?cs 
+        each:tag=also ?><li><?cs
+            if:tag.kind == "@see" ?><code><a href="<?cs var:toroot ?><?cs var:tag.href ?>"><?cs
+                    var:tag.label ?></a></code><?cs
+            elif:tag.kind == "@seeHref" ?><a href="<?cs var:tag.href ?>"><?cs var:tag.label ?></a><?cs
+            elif:tag.kind == "@seeJustLabel" ?><?cs var:tag.label ?><?cs
+            else ?>[ERROR: Unknown @see kind]<?cs
+            /if ?></li><?cs 
+        /each ?>
+      </ul>
+  </div><?cs 
+  /if ?>
+<?cs /def ?>
+
+<?cs # print the API Level ?><?cs
+def:since_tags(obj) ?>
+  Since: <a href="<?cs var:toroot ?>guide/appendix/api-levels.html#level<?cs var:obj.since ?>">API Level <?cs var:obj.since ?></a>
+<?cs /def ?>
+
+<?cs # Print the long-form description for something.
+       Uses the following fields: deprecated descr seeAlso since ?><?cs
+def:description(obj) ?><?cs 
+  call:deprecated_warning(obj) ?>
+  <div class="jd-tagdata jd-tagdescr"><p><?cs call:tag_list(obj.descr) ?></p></div><?cs 
+  if:subcount(obj.attrRefs) ?>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Related XML Attributes</h5>
+      <ul class="nolist"><?cs 
+        each:attr=obj.attrRefs ?>
+            <li><a href="<?cs var:toroot ?><?cs var:attr.href ?>"><?cs var:attr.name ?></a></li><?cs 
+        /each ?>
+      </ul>
+  </div><?cs 
+  /if ?><?cs 
+  if:subcount(obj.paramTags) ?>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Parameters</h5>
+      <table class="jd-tagtable"><?cs 
+      each:tag=obj.paramTags ?>
+        <tr>
+          <th><?cs if:tag.isTypeParameter ?>&lt;<?cs /if ?><?cs var:tag.name
+                  ?><?cs if:tag.isTypeParameter ?>&gt;<?cs /if ?></td>
+          <td><?cs call:tag_list(tag.comment) ?></td>
+        </tr><?cs 
+      /each ?>
+      </table>
+  </div><?cs 
+  /if ?><?cs 
+  if:subcount(obj.returns) ?>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist"><li><?cs call:tag_list(obj.returns) ?></li></ul>
+  </div><?cs 
+  /if ?><?cs 
+  if:subcount(obj.throws) ?>
+  <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Throws</h5>
+      <table class="jd-tagtable"><?cs 
+      each:tag=obj.throws ?>  
+        <tr>
+            <th><?cs call:type_link(tag.type) ?></td>
+            <td><?cs call:tag_list(tag.comment) ?></td>
+        </tr><?cs 
+      /each ?>
+      </table>
+  </div><?cs 
+  /if ?><?cs 
+  call:see_also_tags(obj.seeAlso) ?><?cs
+/def ?>
+
+<?cs # A table of links to classes with descriptions, as in a package file or the nested classes ?><?cs
+def:class_link_table(classes) ?><?cs 
+  set:count = #1 ?>
+  <table class="jd-sumtable-expando"><?cs
+      each:cl=classes ?>
+        <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:cl.type.since ?>" >
+              <td class="jd-linkcol"><?cs call:type_link(cl.type) ?></td>
+              <td class="jd-descrcol" width="100%"><?cs call:short_descr(cl) ?>&nbsp;</td>
+          </tr><?cs set:count = count + #1 ?><?cs
+      /each ?>
+  </table><?cs 
+/def ?>
+
+<?cs # A list of links to classes, for use in the side navigation of classes when viewing a package (panel nav) ?><?cs 
+def:class_link_list(label, classes) ?><?cs 
+  if:subcount(classes) ?>
+    <li><h2><?cs var:label ?></h2>
+      <ul><?cs 
+      each:cl=classes ?>
+        <li class="api apilevel-<?cs var:cl.type.since ?>"><?cs call:type_link(cl.type) ?></li><?cs 
+      /each ?>
+      </ul>
+    </li><?cs 
+  /if ?><?cs 
+/def ?>
+
+<?cs # A list of links to classes, for use in the side navigation of classes when viewing a class (panel nav) ?><?cs 
+def:list(label, classes) ?><?cs 
+  if:subcount(classes) ?>
+    <li><h2><?cs var:label ?></h2>
+      <ul><?cs 
+      each:cl=classes ?>
+          <li class="<?cs if:class.name == cl.label?>selected <?cs /if ?>api apilevel-<?cs var:cl.since ?>"><?cs call:type_link(cl) ?></li><?cs 
+      /each ?>
+      </ul>
+    </li><?cs 
+  /if ?><?cs 
+/def ?>
+
+<?cs # A list of links to packages, for use in the side navigation of packages (panel nav) ?><?cs 
+def:package_link_list(packages) ?><?cs 
+  each:pkg=packages ?>
+    <li class="<?cs if:(class.package.name == pkg.name) || (package.name == pkg.name)?>selected <?cs /if ?>api apilevel-<?cs var:pkg.since ?>"><?cs call:package_link(pkg) ?></li><?cs 
+  /each ?><?cs
+/def ?>
+
+<?cs # An expando trigger ?><?cs 
+def:expando_trigger(id, default) ?>
+  <a href="#" onclick="return toggleInherited(this, null)" id="<?cs var:id ?>" class="jd-expando-trigger closed"
+          ><img id="<?cs var:id ?>-trigger"
+          src="<?cs var:toroot ?>assets/images/triangle-<?cs var:default ?>.png"
+          class="jd-expando-trigger-img" /></a><?cs 
+/def ?>
+
+<?cs # An expandable list of classes ?><?cs 
+def:expandable_class_list(id, classes, default) ?>
+  <div id="<?cs var:id ?>">
+      <div id="<?cs var:id ?>-list"
+              class="jd-inheritedlinks"
+              <?cs if:default != "list" ?>style="display: none;"<?cs /if ?>
+              ><?cs 
+          each:cl=classes ?>
+              <?cs call:type_link(cl.type) ?><?cs if:!last(cl) ?>,<?cs /if ?><?cs 
+          /each ?>
+      </div>
+      <div id="<?cs var:id ?>-summary"
+              <?cs if:default != "summary" ?>style="display: none;"<?cs /if ?>
+              ><?cs 
+          call:class_link_table(classes) ?>
+      </div>
+  </div><?cs 
+/def ?>
+
+
+<?cs include:"customization.cs" ?>
diff --git a/build/tools/droiddoc/templates/navtree_data.cs b/build/tools/droiddoc/templates/navtree_data.cs
new file mode 100644 (file)
index 0000000..c707232
--- /dev/null
@@ -0,0 +1,4 @@
+var NAVTREE_DATA =
+<?cs var:reference_tree ?>
+;
+
diff --git a/build/tools/droiddoc/templates/nosidenavpage.cs b/build/tools/droiddoc/templates/nosidenavpage.cs
new file mode 100644 (file)
index 0000000..1dec41e
--- /dev/null
@@ -0,0 +1,23 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<body class="gc-documentation">
+<a name="top"></a>
+<?cs call:custom_masthead() ?>
+
+<div id="body-content">
+<div id="doc-content" style="position:relative;">
+
+<?cs call:tag_list(root.descr) ?>
+
+<?cs include:"footer.cs" ?>
+</div><!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
+
+
+
diff --git a/build/tools/droiddoc/templates/package-descr.cs b/build/tools/droiddoc/templates/package-descr.cs
new file mode 100644 (file)
index 0000000..08fee18
--- /dev/null
@@ -0,0 +1,38 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<body class="<?cs var:package.since ?>">
+<?cs include:"header.cs" ?>
+
+<div class="g-unit" id="doc-content">
+
+<div id="api-info-block">
+<div class="api-level">
+  <?cs call:since_tags(package) ?>
+</div>
+</div>
+
+<div id="jd-header">
+  package
+  <h1><?cs var:package.name ?></b></h1>
+  <div class="jd-nav">
+      <a class="jd-navlink" href="package-summary.html">Classes</a> | Description
+  </div>
+</div><!-- end header -->
+
+<div id="naMessage"></div>
+
+<div id="jd-content" class="api apilevel-<?cs var:package.since ?>">
+<div class="jd-descr">
+<p><?cs call:tag_list(package.descr) ?></p>
+</div>
+
+<?cs include:"footer.cs" ?>
+</div><!-- end jd-content -->
+</div> <!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
diff --git a/build/tools/droiddoc/templates/package-list.cs b/build/tools/droiddoc/templates/package-list.cs
new file mode 100644 (file)
index 0000000..7f0f889
--- /dev/null
@@ -0,0 +1,2 @@
+<?cs each:pkg=docs.packages ?><?cs var: pkg.name ?>
+<?cs /each ?>
diff --git a/build/tools/droiddoc/templates/package.cs b/build/tools/droiddoc/templates/package.cs
new file mode 100644 (file)
index 0000000..b29bc77
--- /dev/null
@@ -0,0 +1,59 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<body class="<?cs var:package.since ?>">
+<?cs include:"header.cs" ?>
+
+<div class="g-unit" id="doc-content">
+
+<div id="api-info-block">
+<div class="api-level">
+  <?cs call:since_tags(package) ?>
+</div>
+</div>
+
+<div id="jd-header">
+  package
+  <h1><?cs var:package.name ?></h1>
+  <div class="jd-nav">
+      <?cs if:subcount(package.shortDescr) ?>
+        Classes | <a class="jd-navlink" href="package-descr.html">Description</a>
+      <?cs /if ?>
+  </div>
+</div><!-- end header -->
+
+<div id="naMessage"></div>
+
+<div id="jd-content" class="api apilevel-<?cs var:package.since ?>">
+
+<?cs if:subcount(package.shortDescr) ?>
+  <div class="jd-descr">
+  <p><?cs call:tag_list(package.shortDescr) ?></p>
+  <p><span class="jd-more"><a href="package-descr.html">more...</a></span></p>
+  </div>
+<?cs /if ?>
+
+<?cs def:class_table(label, classes) ?>
+  <?cs if:subcount(classes) ?>
+    <h3><?cs var:label ?></h3>
+    <div class="jd-sumtable">
+    <?cs call:class_link_table(classes) ?>
+    </div>
+  <?cs /if ?>
+<?cs /def ?>
+
+<?cs call:class_table("Interfaces", package.interfaces) ?>
+<?cs call:class_table("Classes", package.classes) ?>
+<?cs call:class_table("Enums", package.enums) ?>
+<?cs call:class_table("Exceptions", package.exceptions) ?>
+<?cs call:class_table("Errors", package.errors) ?>
+
+<?cs include:"footer.cs" ?>
+</div><!-- end jd-content -->
+</div><!-- doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
diff --git a/build/tools/droiddoc/templates/packages.cs b/build/tools/droiddoc/templates/packages.cs
new file mode 100644 (file)
index 0000000..8650ad1
--- /dev/null
@@ -0,0 +1,38 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<body class="gc-documentation">
+<?cs include:"header.cs" ?>
+
+<div class="g-unit" id="doc-content">
+
+<div id="jd-header">
+<h1><?cs var:page.title ?></h1>
+</div>
+
+<div id="jd-content">
+
+<div class="jd-descr">
+<p><?cs call:tag_list(root.descr) ?></p>
+</div>
+
+<?cs set:count = #1 ?>
+<table class="jd-sumtable">
+<?cs each:pkg = docs.packages ?>
+    <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:pkg.since ?>" >
+        <td class="jd-linkcol"><?cs call:package_link(pkg) ?></td>
+        <td class="jd-descrcol" width="100%"><?cs call:tag_list(pkg.shortDescr) ?></td>
+    </tr>
+<?cs set:count = count + #1 ?>
+<?cs /each ?>
+</table>
+
+<?cs include:"footer.cs" ?>
+</div><!-- end jd-content -->
+</div> <!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
diff --git a/build/tools/droiddoc/templates/sample.cs b/build/tools/droiddoc/templates/sample.cs
new file mode 100644 (file)
index 0000000..7979b2a
--- /dev/null
@@ -0,0 +1,32 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<?cs set:resources="true" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<?cs include:"header.cs" ?>
+<body class="gc-documentation">
+
+
+<a name="top"></a>
+<div class="g-unit" id="doc-content">
+ <div id="jd-header" class="guide-header">
+  <span class="crumb">&nbsp;</span>
+  <h1><?cs var:page.title ?></h1>
+ </div>
+
+<div id="jd-content">
+
+<p>The file containing the source code shown below is located in the corresponding directory in <code>&lt;sdk&gt;/platforms/android-&lt;version&gt;/samples/...</code></p>
+
+<!-- begin file contents -->
+<pre><?cs var:fileContents ?></pre>
+<!-- end file contents -->
+
+<?cs include:"footer.cs" ?>
+</div><!-- end jd-content -->
+</div> <!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
diff --git a/build/tools/droiddoc/templates/sampleindex.cs b/build/tools/droiddoc/templates/sampleindex.cs
new file mode 100644 (file)
index 0000000..8a75298
--- /dev/null
@@ -0,0 +1,64 @@
+<?cs include:"doctype.cs" ?>
+<?cs include:"macros.cs" ?>
+<?cs set:resources="true" ?>
+<html>
+<?cs include:"head_tag.cs" ?>
+<?cs include:"header.cs" ?>
+<body class="gc-documentation">
+
+
+<a name="top"></a>
+<div class="g-unit" id="doc-content">
+ <div id="jd-header" class="guide-header">
+  <span class="crumb">&nbsp;</span>
+  <h1><?cs var:page.title ?></h1>
+ </div>
+
+<div id="jd-content">
+
+<?cs var:summary ?>
+
+<?cs if:android.whichdoc == "online" ?><?cs
+  # If this is the online docs, build the src code navigation links ?>
+
+  <?cs if:subcount(subdirs) ?>
+      <h2>Subdirectories</h2>
+      <ul class="nolist">
+      <?cs each:dir=subdirs ?>
+        <li><a href="<?cs var:dir.name ?>/index.html"><?cs
+          var:dir.name ?>/</a></li>
+      <?cs /each ?>
+      </ul>
+  <?cs /if ?>
+
+  <?cs if:subcount(files) ?>
+      <h2>Files</h2>
+      <ul class="nolist">
+      <?cs each:file=files ?>
+        <li><a href="<?cs var:file.href ?>"><?cs
+          var:file.name ?></a></li>
+      <?cs /each ?>
+      </ul>
+  <?cs /if ?>
+
+<?cs else ?><?cs
+  # else, this means it's offline docs,
+          so don't show src links (we don't have the pages!) ?>
+
+<p>You can find the source code for this sample in your SDK at:</p>
+<p style="margin-left:2em">
+<code><em>&lt;sdk&gt;</em>/platforms/android-<em>&lt;version&gt;</em>/samples/</code>
+</p>
+
+<?cs /if ?><?cs # end if/else online docs ?>
+
+</div><!-- end jd-content -->
+
+<?cs include:"footer.cs" ?>
+
+</div><!-- end doc-content -->
+
+<?cs include:"trailer.cs" ?>
+
+</body>
+</html>
diff --git a/build/tools/droiddoc/templates/todo.cs b/build/tools/droiddoc/templates/todo.cs
new file mode 100644 (file)
index 0000000..e9f7237
--- /dev/null
@@ -0,0 +1,99 @@
+<html>
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+    <title><?cs var:page.title ?></title>
+    <style type="text/css">
+    table {
+        border-width: 1px 1px 1px 1px;
+        border-spacing: 0px;
+        border-style: solid solid solid solid;
+        border-color: black black black black;
+        border-collapse: collapse;
+        background-color: white;
+    }
+    table th {
+        border-width: 1px 1px 1px 1px;
+        padding: 1px 4px 1px 3px;
+        border-style: inset inset inset inset;
+        border-color: gray gray gray gray;
+        background-color: white;
+    }
+    table td {
+        border-width: 1px 1px 1px 1px;
+        padding: 1px 4px 1px 3px;
+        border-style: inset inset inset inset;
+        border-color: gray gray gray gray;
+        background-color: white;
+    }
+    </style>
+</head>
+<body>
+<h1><?cs var:page.title ?></h1>
+
+<h2>Overall</h2>
+<table>
+<tr><th>Errors</th><td><?cs var:all.errorCount ?></td></tr>
+<tr><th>Percent Good</th><td><?cs var:all.percentGood ?></td></tr>
+<tr><th>Total Comments</th><td><?cs var:all.totalCount ?></td></tr>
+</table>
+
+<h2>Package Summary</h2>
+
+<table>
+<tr>
+    <th>Package</th>
+    <th>Errors</th>
+    <th>Percent Good</th>
+    <th>Total</th>
+</tr>
+<?cs each:pkg=packages ?>
+<tr>
+    <td><?cs var:pkg.name ?></td>
+    <td><?cs var:pkg.errorCount ?></td>
+    <td><?cs var:pkg.percentGood ?></td>
+    <td><?cs var:pkg.totalCount ?></td>
+</tr>
+<?cs /each ?>
+</table>
+
+
+<h2>Class Summary</h3>
+
+<table>
+<tr>
+    <th>Class</th>
+    <th>Errors</th>
+    <th>Percent Good</th>
+    <th>Total</th>
+</tr>
+<?cs each:cl=classes ?>
+<tr>
+    <td><a href="#class_<?cs var:cl.qualified ?>"><?cs var:cl.qualified ?></a></td>
+    <td><?cs var:cl.errorCount ?></td>
+    <td><?cs var:cl.percentGood ?></td>
+    <td><?cs var:cl.totalCount ?></td>
+</tr>
+<?cs /each ?>
+</table>
+
+<h2>Detail</h2>
+
+<?cs each:cl=classes ?>
+<h3><a name="class_<?cs var:cl.qualified ?>"><?cs var:cl.qualified ?></a></h3>
+<p>Errors: <?cs var:cl.errorCount ?><br/>
+Total: <?cs var:cl.totalCount ?><br/>
+Percent Good: <?cs var:cl.percentGood ?></p>
+<table>
+<?cs each:err=cl.errors ?>
+<tr>
+    <td><?cs var:err.pos ?></td>
+    <td><?cs var:err.name ?></td>
+    <td><?cs var:err.descr ?></td>
+</tr>
+<?cs /each ?>
+</table>
+
+<?cs /each ?>
+
+</body>
+</html>
diff --git a/build/tools/droiddoc/templates/trailer.cs b/build/tools/droiddoc/templates/trailer.cs
new file mode 100644 (file)
index 0000000..155ba58
--- /dev/null
@@ -0,0 +1,11 @@
+</div> <!-- end body-content --> <?cs # normally opened by header.cs ?>
+
+<script type="text/javascript">
+init(); /* initialize android-developer-docs.js */
+var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+</script>
+<script type="text/javascript">
+var pageTracker = _gat._getTracker("UA-5831155-1");
+pageTracker._trackPageview();
+</script>
\ No newline at end of file
diff --git a/build/tools/droiddoc/test/generics/Android.mk b/build/tools/droiddoc/test/generics/Android.mk
new file mode 100644 (file)
index 0000000..0c808fd
--- /dev/null
@@ -0,0 +1,28 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=$(call all-subdir-java-files)
+
+LOCAL_MODULE:=test_generics
+LOCAL_DROIDDOC_OPTIONS:=\
+        -stubs __test_generics__
+
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=tools/droiddoc/templates-google
+LOCAL_DROIDDOC_CUSTOM_ASSET_DIR:=assets-google
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+include $(BUILD_DROIDDOC)
diff --git a/build/tools/droiddoc/test/generics/src/com/android/generics/AbsListView.java b/build/tools/droiddoc/test/generics/src/com/android/generics/AbsListView.java
new file mode 100644 (file)
index 0000000..6bef812
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.generics;
+
+public class AbsListView implements AdapterView<ListAdapter> {
+}
diff --git a/build/tools/droiddoc/test/generics/src/com/android/generics/Adapter.java b/build/tools/droiddoc/test/generics/src/com/android/generics/Adapter.java
new file mode 100644 (file)
index 0000000..c041dd1
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.generics;
+
+public class Adapter {
+}
diff --git a/build/tools/droiddoc/test/generics/src/com/android/generics/AdapterView.java b/build/tools/droiddoc/test/generics/src/com/android/generics/AdapterView.java
new file mode 100644 (file)
index 0000000..de4f8f1
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.generics;
+
+public interface AdapterView<T extends Adapter> {
+}
+
diff --git a/build/tools/droiddoc/test/generics/src/com/android/generics/Bar.java b/build/tools/droiddoc/test/generics/src/com/android/generics/Bar.java
new file mode 100644 (file)
index 0000000..bd9fcbc
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.generics;
+
+public interface Bar<K> {
+    public K bar(K arg);
+}
+
diff --git a/build/tools/droiddoc/test/generics/src/com/android/generics/Foo.java b/build/tools/droiddoc/test/generics/src/com/android/generics/Foo.java
new file mode 100644 (file)
index 0000000..d5d07eb
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.generics;
+
+public class Foo<V> {
+    public Foo(V v) {
+    }
+
+    public V foo(V arg) {
+        return null;
+    }
+}
+
+
diff --git a/build/tools/droiddoc/test/generics/src/com/android/generics/FooBar.java b/build/tools/droiddoc/test/generics/src/com/android/generics/FooBar.java
new file mode 100644 (file)
index 0000000..7ea3567
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.generics;
+
+public class FooBar<K,V,L> extends Foo<V> implements Bar<K> {
+    public class C
+    {
+    }
+
+    public class CI extends C implements Iface
+    {
+    }
+
+    public FooBar(K k) {
+        super(null);
+        throw new RuntimeException("!");
+    }
+
+    public K bar(K arg) {
+        return null;
+    }
+    
+    public FooBar<K,? extends Foo,L> a(K arg) {
+        return null;
+    }
+
+    public FooBar<V,K,L> b(Bar<? extends K> arg) {
+        return null;
+    }
+
+    public <L extends C & Iface> void f(L arg) {
+    }
+
+    public V v;
+}
+
+
diff --git a/build/tools/droiddoc/test/generics/src/com/android/generics/Iface.java b/build/tools/droiddoc/test/generics/src/com/android/generics/Iface.java
new file mode 100644 (file)
index 0000000..03aa2dd
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.generics;
+
+public interface Iface {
+}
diff --git a/build/tools/droiddoc/test/generics/src/com/android/generics/ListAdapter.java b/build/tools/droiddoc/test/generics/src/com/android/generics/ListAdapter.java
new file mode 100644 (file)
index 0000000..5f88a56
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.generics;
+
+public class ListAdapter extends Adapter {
+}
diff --git a/build/tools/droiddoc/test/generics/src/com/android/generics/TestComparable.java b/build/tools/droiddoc/test/generics/src/com/android/generics/TestComparable.java
new file mode 100644 (file)
index 0000000..9d394ae
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.generics;
+
+public interface TestComparable<T> {
+}
diff --git a/build/tools/droiddoc/test/generics/src/com/android/generics/TestEnum.java b/build/tools/droiddoc/test/generics/src/com/android/generics/TestEnum.java
new file mode 100644 (file)
index 0000000..efb1d18
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.generics;
+
+public class TestEnum<E extends TestEnum<E>> implements TestComparable<E> {
+}
+
diff --git a/build/tools/droiddoc/test/stubs/Android.mk b/build/tools/droiddoc/test/stubs/Android.mk
new file mode 100644 (file)
index 0000000..fc971e1
--- /dev/null
@@ -0,0 +1,29 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=$(call all-java-files-under,src)
+
+LOCAL_MODULE:=test_stubs
+LOCAL_DROIDDOC_OPTIONS:=\
+        -stubs $(OUT_DIR)/__test_stubs__
+
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=tools/droiddoc/templates-google
+LOCAL_DROIDDOC_CUSTOM_ASSET_DIR:=assets-google
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+include $(BUILD_DROIDDOC)
+
diff --git a/build/tools/droiddoc/test/stubs/expected/com/android/stubs/Annot.java b/build/tools/droiddoc/test/stubs/expected/com/android/stubs/Annot.java
new file mode 100644 (file)
index 0000000..b6144b6
--- /dev/null
@@ -0,0 +1,8 @@
+package com.android.stubs;
+@java.lang.annotation.Documented()
+@java.lang.annotation.Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
+@java.lang.annotation.Target(value={java.lang.annotation.ElementType.TYPE})
+public @interface Annot
+{
+java.lang.String value() default "yo\u1234";
+}
diff --git a/build/tools/droiddoc/test/stubs/expected/com/android/stubs/InterfaceEnum.java b/build/tools/droiddoc/test/stubs/expected/com/android/stubs/InterfaceEnum.java
new file mode 100644 (file)
index 0000000..b0c87e7
--- /dev/null
@@ -0,0 +1,9 @@
+package com.android.stubs;
+public enum InterfaceEnum
+  implements com.android.stubs.Parent.Interface
+{
+VAL();
+public  void method() { throw new RuntimeException("Stub!"); }
+public static final java.lang.Object OBJECT;
+static { OBJECT = null; }
+}
diff --git a/build/tools/droiddoc/test/stubs/expected/com/android/stubs/Parent.java b/build/tools/droiddoc/test/stubs/expected/com/android/stubs/Parent.java
new file mode 100644 (file)
index 0000000..132d566
--- /dev/null
@@ -0,0 +1,27 @@
+package com.android.stubs;
+@com.android.stubs.Annot(value="asdf")
+public class Parent
+{
+public static interface Interface
+{
+public  void method();
+}
+public  Parent() { throw new RuntimeException("Stub!"); }
+public  java.lang.String methodString() { throw new RuntimeException("Stub!"); }
+public  int method(boolean b, char c, int i, long l, float f, double d) { throw new RuntimeException("Stub!"); }
+protected  void protectedMethod() { throw new RuntimeException("Stub!"); }
+public static final byte public_static_final_byte = 42;
+public static final short public_static_final_short = 43;
+public static final int public_static_final_int = 44;
+public static final long public_static_final_long = 45L;
+public static final char public_static_final_char = 4660;
+public static final float public_static_final_float = 42.1f;
+public static final double public_static_final_double = 42.2;
+public static int public_static_int;
+public static final java.lang.String public_static_final_String = "ps\u1234fS";
+public static java.lang.String public_static_String;
+public static com.android.stubs.Parent public_static_Parent;
+public static final com.android.stubs.Parent public_static_final_Parent;
+public static final com.android.stubs.Parent public_static_final_Parent_null;
+static { public_static_final_Parent = null; public_static_final_Parent_null = null; }
+}
diff --git a/build/tools/droiddoc/test/stubs/expected/com/android/stubs/SomeEnum.java b/build/tools/droiddoc/test/stubs/expected/com/android/stubs/SomeEnum.java
new file mode 100644 (file)
index 0000000..ecfd9d4
--- /dev/null
@@ -0,0 +1,7 @@
+package com.android.stubs;
+public enum SomeEnum
+{
+A(),
+B(),
+C();
+}
diff --git a/build/tools/droiddoc/test/stubs/expected/com/android/stubs/Types.java b/build/tools/droiddoc/test/stubs/expected/com/android/stubs/Types.java
new file mode 100644 (file)
index 0000000..3f5a791
--- /dev/null
@@ -0,0 +1,33 @@
+package com.android.stubs;
+public class Types
+{
+public static interface Interface
+{
+public static final boolean public_static_final_boolean = false;
+public static final char public_static_final_char = 0;
+public static final short public_static_final_short = 0;
+public static final int public_static_final_int = 0;
+public static final long public_static_final_long = 0L;
+public static final float public_static_final_float = 0.0f;
+public static final double public_static_final_double = 0.0;
+public static final java.lang.Object public_static_final_Object = null;
+}
+protected  Types() { throw new RuntimeException("Stub!"); }
+public final boolean public_final_boolean;
+public final char public_final_char;
+public final short public_final_short;
+public final int public_final_int;
+public final long public_final_long;
+public final float public_final_float;
+public final double public_final_double;
+public final java.lang.Object public_final_Object;
+public static final boolean public_static_final_boolean;
+public static final char public_static_final_char;
+public static final short public_static_final_short;
+public static final int public_static_final_int;
+public static final long public_static_final_long;
+public static final float public_static_final_float;
+public static final double public_static_final_double;
+public static final java.lang.Object public_static_final_Object;
+static { public_static_final_boolean = false; public_static_final_char = 0; public_static_final_short = 0; public_static_final_int = 0; public_static_final_long = 0; public_static_final_float = 0; public_static_final_double = 0; public_static_final_Object = null; }
+}
diff --git a/build/tools/droiddoc/test/stubs/expected/com/android/stubs/a/A.java b/build/tools/droiddoc/test/stubs/expected/com/android/stubs/a/A.java
new file mode 100644 (file)
index 0000000..f3cb888
--- /dev/null
@@ -0,0 +1,14 @@
+package com.android.stubs.a;
+public abstract class A
+  extends com.android.stubs.Parent
+  implements com.android.stubs.Parent.Interface, com.android.stubs.a.SomeInterface
+{
+public class Inner
+{
+public  Inner() { throw new RuntimeException("Stub!"); }
+}
+protected  A(int a) { throw new RuntimeException("Stub!"); }
+public  com.android.stubs.a.A varargs(com.android.stubs.Parent[]... args) { throw new RuntimeException("Stub!"); }
+public  void method() { throw new RuntimeException("Stub!"); }
+public abstract  java.lang.String[] stringArrayMethod() throws java.io.IOException;
+}
diff --git a/build/tools/droiddoc/test/stubs/expected/com/android/stubs/a/SomeInterface.java b/build/tools/droiddoc/test/stubs/expected/com/android/stubs/a/SomeInterface.java
new file mode 100644 (file)
index 0000000..c24981b
--- /dev/null
@@ -0,0 +1,4 @@
+package com.android.stubs.a;
+public interface SomeInterface
+{
+}
diff --git a/build/tools/droiddoc/test/stubs/expected/com/android/stubs/b/B.java b/build/tools/droiddoc/test/stubs/expected/com/android/stubs/b/B.java
new file mode 100644 (file)
index 0000000..5db2fce
--- /dev/null
@@ -0,0 +1,5 @@
+package com.android.stubs.b;
+public class B
+{
+public  B() { throw new RuntimeException("Stub!"); }
+}
diff --git a/build/tools/droiddoc/test/stubs/func.sh b/build/tools/droiddoc/test/stubs/func.sh
new file mode 100644 (file)
index 0000000..ea4fe75
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/sh
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+export A_STUBS=out/stubs/a/stubs
+export B_STUBS=out/stubs/b/stubs
+export EXPECTED_STUBS=out/stubs/expected/stubs
+export EXPECTED=$DIR/expected
+
+function build_stubs()
+{
+    ID=$1
+    SRC_DIR=$2
+    STUBS_DIR=$3
+
+    OBJ_DIR=out/stubs/$ID
+    PLATFORM=${HOST_OS}-${HOST_ARCH}
+
+    rm -rf $OBJ_DIR &> /dev/null
+    mkdir -p $OBJ_DIR
+
+    find $SRC_DIR -name '*.java' > $OBJ_DIR/javadoc-src-list
+    ( \
+        LD_LIBRARY_PATH=out/host/$PLATFORM/lib \
+        javadoc \
+            \@$OBJ_DIR/javadoc-src-list \
+            -J-Xmx512m \
+            -J-Djava.library.path=out/host/$PLATFORM/lib \
+             \
+            -quiet \
+            -doclet DroidDoc \
+            -docletpath out/host/$PLATFORM/framework/clearsilver.jar:out/host/$PLATFORM/framework/droiddoc.jar:out/host/$PLATFORM/framework/apicheck.jar \
+            -templatedir tools/droiddoc/templates \
+            -classpath out/target/common/obj/JAVA_LIBRARIES/core_intermediates/classes.jar:out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/classes.jar:out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar \
+            -sourcepath $SRC_DIR:out/target/common/obj/JAVA_LIBRARIES/core_intermediates/classes.jar:out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/classes.jar:out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar \
+            -d $OBJ_DIR/docs \
+            -hdf page.build MAIN-eng.joeo.20080710.121320 -hdf page.now "10 Jul 2008 12:13" \
+            -stubs $STUBS_DIR \
+            -stubpackages com.android.stubs:com.android.stubs.a:com.android.stubs.b:com.android.stubs.hidden \
+        && rm -rf $OBJ_DIR/docs/assets \
+        && mkdir -p $OBJ_DIR/docs/assets \
+        && cp -fr tools/droiddoc/templates/assets/* $OBJ_DIR/docs/assets/ \
+    )# || (rm -rf $OBJ_DIR; exit 45)
+}
+
+function compile_stubs()
+{
+    ID=$1
+    STUBS_DIR=$2
+
+    OBJ_DIR=out/stubs/$ID
+    CLASS_DIR=$OBJ_DIR/class
+    mkdir -p $CLASS_DIR
+
+    find $STUBS_DIR -name "*.java" > $OBJ_DIR/java-src-list
+    javac @$OBJ_DIR/java-src-list -d $CLASS_DIR
+}
diff --git a/build/tools/droiddoc/test/stubs/run.sh b/build/tools/droiddoc/test/stubs/run.sh
new file mode 100644 (file)
index 0000000..2ea15a6
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+DIR=build/tools/droiddoc/test/stubs
+
+pushd $TOP
+
+. $TOP/$DIR/func.sh
+
+mkdir -p out/stubs_compiled
+find $DIR/src -name "*.java" | xargs javac -d out/stubs_compiled
+
+build_stubs a $DIR/src $A_STUBS
+build_stubs b $A_STUBS $B_STUBS
+
+compile_stubs a $A_STUBS
+
+echo EXPECTED
+diff -r $DIR/expected $A_STUBS
+echo TWICE STUBBED
+diff -r $A_STUBS $B_STUBS
+
+popd &> /dev/null
+
+
+
diff --git a/build/tools/droiddoc/test/stubs/src/com/android/stubs/Annot.java b/build/tools/droiddoc/test/stubs/src/com/android/stubs/Annot.java
new file mode 100644 (file)
index 0000000..fe9226f
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.stubs;
+
+import java.lang.annotation.*;
+
+/**
+ * poop
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface Annot {
+    String value() default "yo\u1234";
+}
+
diff --git a/build/tools/droiddoc/test/stubs/src/com/android/stubs/InterfaceEnum.java b/build/tools/droiddoc/test/stubs/src/com/android/stubs/InterfaceEnum.java
new file mode 100644 (file)
index 0000000..1e64f57
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.stubs;
+
+public enum InterfaceEnum implements Parent.Interface {
+    VAL;
+    public static final Object OBJECT = new Object();
+    public void method() { }
+}
diff --git a/build/tools/droiddoc/test/stubs/src/com/android/stubs/Parent.java b/build/tools/droiddoc/test/stubs/src/com/android/stubs/Parent.java
new file mode 100644 (file)
index 0000000..577db38
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.stubs;
+
+@Annot("asdf")
+public class Parent {
+    public static final byte public_static_final_byte = 42;
+    public static final short public_static_final_short = 43;
+    public static final int public_static_final_int = 44;
+    public static final long public_static_final_long = 45;
+    public static final char public_static_final_char = '\u1234';
+    public static final float public_static_final_float = 42.1f;
+    public static final double public_static_final_double = 42.2;
+    public static int public_static_int = 1;
+    public static final String public_static_final_String = "ps\u1234fS";
+    public static String public_static_String = "psS";
+    public static Parent public_static_Parent = new Parent();
+    public static final Parent public_static_final_Parent = new Parent();
+    public static final Parent public_static_final_Parent_null = null;
+
+    public interface Interface {
+        void method();
+    }
+
+    public Parent() {
+    }
+
+    public String methodString() {
+        return "yo";
+    }
+
+    public int method(boolean b, char c, int i, long l, float f, double d) {
+        return 1;
+    }
+
+    protected void protectedMethod() {
+    }
+
+    void packagePrivateMethod() {
+    }
+
+    /** @hide */
+    public void hiddenMethod() {
+    }
+}
+
diff --git a/build/tools/droiddoc/test/stubs/src/com/android/stubs/SomeEnum.java b/build/tools/droiddoc/test/stubs/src/com/android/stubs/SomeEnum.java
new file mode 100644 (file)
index 0000000..51c5000
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.stubs;
+
+public enum SomeEnum {
+    A, B, C
+}
diff --git a/build/tools/droiddoc/test/stubs/src/com/android/stubs/Types.java b/build/tools/droiddoc/test/stubs/src/com/android/stubs/Types.java
new file mode 100644 (file)
index 0000000..5e24a10
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.stubs;
+
+public class Types {
+    public final boolean public_final_boolean;
+    public final char public_final_char;
+    public final short public_final_short;
+    public final int public_final_int;
+    public final long public_final_long;
+    public final float public_final_float;
+    public final double public_final_double;
+    public final Object public_final_Object;
+
+    public static final boolean public_static_final_boolean;
+    public static final char public_static_final_char;
+    public static final short public_static_final_short;
+    public static final int public_static_final_int;
+    public static final long public_static_final_long;
+    public static final float public_static_final_float;
+    public static final double public_static_final_double;
+    public static final Object public_static_final_Object;
+
+    /** @hide */
+    public Types() {
+        public_final_boolean = false;
+        public_final_char = 0;
+        public_final_short = 0;
+        public_final_int = 0;
+        public_final_long = 0;
+        public_final_float = 0;
+        public_final_double = 0;
+        public_final_Object = null;
+    }
+
+    static {
+        public_static_final_boolean = false;
+        public_static_final_char = 0;
+        public_static_final_short = 0;
+        public_static_final_int = 0;
+        public_static_final_long = 0;
+        public_static_final_float = 0;
+        public_static_final_double = 0;
+        public_static_final_Object = null;
+    }
+
+    public interface Interface {
+        public static final boolean public_static_final_boolean = false;
+        public static final char public_static_final_char = 0;
+        public static final short public_static_final_short = 0;
+        public static final int public_static_final_int = 0;
+        public static final long public_static_final_long = 0;
+        public static final float public_static_final_float = 0;
+        public static final double public_static_final_double = 0;
+        public static final Object public_static_final_Object = null;
+    }
+}
+
diff --git a/build/tools/droiddoc/test/stubs/src/com/android/stubs/a/A.java b/build/tools/droiddoc/test/stubs/src/com/android/stubs/a/A.java
new file mode 100644 (file)
index 0000000..cebeaf1
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.stubs.a;
+
+import com.android.stubs.Parent;
+
+public abstract class A extends Parent implements Parent.Interface, SomeInterface {
+    protected A(int a) {
+        super();
+    }
+
+    public A varargs(Parent... args) {
+        return null;
+    }
+
+    public void method() {
+    }
+    public abstract String[] stringArrayMethod() throws java.io.IOException;
+
+    public class Inner {
+        int method() {
+            return 1;
+        }
+        int field;
+    }
+}
+
diff --git a/build/tools/droiddoc/test/stubs/src/com/android/stubs/a/SomeInterface.java b/build/tools/droiddoc/test/stubs/src/com/android/stubs/a/SomeInterface.java
new file mode 100644 (file)
index 0000000..6f5c3e0
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.stubs.a;
+
+public interface SomeInterface {
+}
+
diff --git a/build/tools/droiddoc/test/stubs/src/com/android/stubs/b/B.java b/build/tools/droiddoc/test/stubs/src/com/android/stubs/b/B.java
new file mode 100644 (file)
index 0000000..7febe33
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.stubs.b;
+
+import com.android.stubs.Parent;
+import com.android.stubs.a.A;
+
+public class B {
+    Parent method(Parent p) {
+        return null;
+    }
+}
diff --git a/build/tools/droiddoc/test/stubs/src/com/android/stubs/hidden/Hidden.java b/build/tools/droiddoc/test/stubs/src/com/android/stubs/hidden/Hidden.java
new file mode 100644 (file)
index 0000000..39ece6e
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.stubs.c;
+
+/** @hide */
+public class Hidden {
+
+}
+
diff --git a/build/tools/droiddoc/test/stubs/src/com/android/stubs/hidden/HiddenOuter.java b/build/tools/droiddoc/test/stubs/src/com/android/stubs/hidden/HiddenOuter.java
new file mode 100644 (file)
index 0000000..0380f43
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.stubs.c;
+
+/** @hide */
+public class HiddenOuter {
+
+    public class NotHiddenInner {
+    }
+}
+
diff --git a/build/tools/droiddoc/test/stubs/src/com/android/stubs/hidden/PackagePrivate.java b/build/tools/droiddoc/test/stubs/src/com/android/stubs/hidden/PackagePrivate.java
new file mode 100644 (file)
index 0000000..165735c
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.stubs.c;
+
+class PackagePrivate {
+
+}
+
diff --git a/build/tools/dump-package-stats b/build/tools/dump-package-stats
new file mode 100644 (file)
index 0000000..d11e727
--- /dev/null
@@ -0,0 +1,152 @@
+#!/bin/bash
+#
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+PROGNAME=`basename $0`
+
+function fail ()
+{
+    if [ ! -z "$@" ]
+    then
+        echo "$PROGNAME: ERROR: $@" >&2
+    fi
+    echo "$PROGNAME: ERROR: failed." >&2
+    exit 1
+}
+
+function usage ()
+{
+    cat << HERE
+usage: $PROGNAME <.jar/.apk-file-list>
+    Dumps a summary of the compressed and uncompressed sizes of various
+    types of files in each package.  Emits one line per package.
+    Packages must be zipfiles, readable using "unzip".
+
+    Example output line:
+
+        filesize=642684 all=603288/919304 dex=119529/353815 name="out/App.apk"
+
+    filesize: the size of the package on disk
+    name: the name of the package as passed to $PROGNAME
+
+    These fields are presented as <uncompressed bytes>/<compressed bytes>:
+
+        all: the sum of all entries in the package
+        dex: the sum of all "*.dex" entries in the package
+HERE
+    exit 1
+}
+
+if [ $# -lt 1 ]
+then
+    usage
+fi
+
+UNAME=`uname`
+if [ "x$UNAME" = "xDarwin" ]
+then
+    statArgs="-f %z"
+elif [ "x$UNAME" = "xLinux" ]
+then
+    statArgs="-c %s"
+else
+    fail "Unknown uname $UNAME"
+fi
+
+function printFileSize ()
+{
+    stat $statArgs $1
+}
+
+for file
+do
+    if [ ! -f "$file" ]
+    then
+        fail "$file doesn't exist or isn't a file"
+    fi
+    unzip -lv "$file" | awk '
+        BEGIN {
+          total_compressed = 0;
+          total_uncompressed = 0;
+          dex_compressed = 0;
+          dex_uncompressed = 0;
+        }
+
+        # Make sure the output of unzip -lv looks like something we expect.
+        #
+        NR == "1" {
+            if ($1 != "Archive:") {
+                print "'$PROGNAME': ERROR: Unexpected zip listing format" > \
+                        "/dev/stderr";
+                print "'$PROGNAME': ERROR: Line 1 is \"" $0 "\"" > \
+                        "/dev/stderr";
+                failed = 1;
+                exit 1;
+            }
+        }
+        NR == "2" {
+            if (NF != "8" ||
+                $1 != "Length" ||
+                $2 != "Method" ||
+                $3 != "Size" ||
+                ($4 != "Ratio" && $4 != "Cmpr") ||
+                $5 != "Date" ||
+                $6 != "Time" ||
+                $7 != "CRC-32" ||
+                $8 != "Name")
+            {
+                print "'$PROGNAME': ERROR: Unexpected zip listing format" > \
+                        "/dev/stderr";
+                print "'$PROGNAME': ERROR: Line 2 is \"" $0 "\"" > \
+                        "/dev/stderr";
+                failed = 1;
+                exit 1;
+            } else {
+                saw_listing = 1;
+            }
+        }
+
+        # Only look for lines where the ratio is the fourth column;
+        # this filters out the header and footer.
+        #
+        $4 ~ /%$/ {
+            uncompressed = $1;
+            compressed = $3;
+            if ($0 ~ /.dex$/) {
+                dex_compressed += compressed;
+                dex_uncompressed += uncompressed;
+            }
+            total_compressed += compressed;
+            total_uncompressed += uncompressed;
+        }
+        { next }
+
+        END {
+            if (!failed && saw_listing) {
+                print "filesize='$(printFileSize "$file")'",
+                      "all=" total_compressed "/" total_uncompressed,
+                      "dex=" dex_compressed "/" dex_uncompressed,
+                      "name=\"'"$file"'\"";
+            } else {
+                exit 1;
+            }
+        }
+    '
+    if [ $? -ne 0 ]
+    then
+        fail "Could not get stats for $file"
+    fi
+done
diff --git a/build/tools/event_log_tags.py b/build/tools/event_log_tags.py
new file mode 100644 (file)
index 0000000..81e8b39
--- /dev/null
@@ -0,0 +1,127 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""A module for reading and parsing event-log-tags files."""
+
+import re
+import sys
+
+class Tag(object):
+  __slots__ = ["tagnum", "tagname", "description", "filename", "linenum"]
+
+  def __init__(self, tagnum, tagname, description, filename, linenum):
+    self.tagnum = tagnum
+    self.tagname = tagname
+    self.description = description
+    self.filename = filename
+    self.linenum = linenum
+
+
+class TagFile(object):
+  """Read an input event-log-tags file."""
+  def AddError(self, msg, linenum=None):
+    if linenum is None:
+      linenum = self.linenum
+    self.errors.append((self.filename, linenum, msg))
+
+  def AddWarning(self, msg, linenum=None):
+    if linenum is None:
+      linenum = self.linenum
+    self.warnings.append((self.filename, linenum, msg))
+
+  def __init__(self, filename, file_object=None):
+    """'filename' is the name of the file (included in any error
+    messages).  If 'file_object' is None, 'filename' will be opened
+    for reading."""
+    self.errors = []
+    self.warnings = []
+    self.tags = []
+    self.options = {}
+
+    self.filename = filename
+    self.linenum = 0
+
+    if file_object is None:
+      try:
+        file_object = open(filename, "rb")
+      except (IOError, OSError), e:
+        self.AddError(str(e))
+        return
+
+    try:
+      for self.linenum, line in enumerate(file_object):
+        self.linenum += 1
+
+        line = line.strip()
+        if not line or line[0] == '#': continue
+        parts = re.split(r"\s+", line, 2)
+
+        if len(parts) < 2:
+          self.AddError("failed to parse \"%s\"" % (line,))
+          continue
+
+        if parts[0] == "option":
+          self.options[parts[1]] = parts[2:]
+          continue
+
+        if parts[0] == "?":
+          tag = None
+        else:
+          try:
+            tag = int(parts[0])
+          except ValueError:
+            self.AddError("\"%s\" isn't an integer tag or '?'" % (parts[0],))
+            continue
+
+        tagname = parts[1]
+        if len(parts) == 3:
+          description = parts[2]
+        else:
+          description = None
+
+        self.tags.append(Tag(tag, tagname, description,
+                             self.filename, self.linenum))
+    except (IOError, OSError), e:
+      self.AddError(str(e))
+
+
+def BooleanFromString(s):
+  """Interpret 's' as a boolean and return its value.  Raise
+  ValueError if it's not something we can interpret as true or
+  false."""
+  s = s.lower()
+  if s in ("true", "t", "1", "on", "yes", "y"):
+    return True
+  if s in ("false", "f", "0", "off", "no", "n"):
+    return False
+  raise ValueError("'%s' not a valid boolean" % (s,))
+
+
+def WriteOutput(output_file, data):
+  """Write 'data' to the given output filename (which may be None to
+  indicate stdout).  Emit an error message and die on any failure.
+  'data' may be a string or a StringIO object."""
+  if not isinstance(data, str):
+    data = data.getvalue()
+  try:
+    if output_file is None:
+      out = sys.stdout
+      output_file = "<stdout>"
+    else:
+      out = open(output_file, "wb")
+    out.write(data)
+    out.close()
+  except (IOError, OSError), e:
+    print >> sys.stderr, "failed to write %s: %s" % (output_file, e)
+    sys.exit(1)
diff --git a/build/tools/fileslist.py b/build/tools/fileslist.py
new file mode 100644 (file)
index 0000000..ae1b4b6
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import os, sys
+
+def get_file_size(path):
+  st = os.lstat(path)
+  return st.st_size;
+
+def main(argv):
+  output = []
+  roots = argv[1:]
+  for root in roots:
+    base = len(root[:root.rfind(os.path.sep)])
+    for dir, dirs, files in os.walk(root):
+      relative = dir[base:]
+      for f in files:
+        try:
+          row = (
+              get_file_size(os.path.sep.join((dir, f))),
+              os.path.sep.join((relative, f)),
+            )
+          output.append(row)
+        except os.error:
+          pass
+  for row in output:
+    print "%12d  %s" % row
+
+if __name__ == '__main__':
+  main(sys.argv)
+
diff --git a/build/tools/findleaves.py b/build/tools/findleaves.py
new file mode 100644 (file)
index 0000000..0adf188
--- /dev/null
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Finds files with the specified name under a particular directory, stopping
+# the search in a given subdirectory when the file is found.
+#
+
+import os
+import sys
+
+def perform_find(mindepth, prune, dirlist, filename):
+  result = []
+  pruneleaves = set(map(lambda x: os.path.split(x)[1], prune))
+  for rootdir in dirlist:
+    rootdepth = rootdir.count("/")
+    for root, dirs, files in os.walk(rootdir):
+      # prune
+      check_prune = False
+      for d in dirs:
+        if d in pruneleaves:
+          check_prune = True
+          break
+      if check_prune:
+        i = 0
+        while i < len(dirs):
+          if dirs[i] in prune:
+            del dirs[i]
+          else:
+            i += 1
+      # mindepth
+      if mindepth > 0:
+        depth = 1 + root.count("/") - rootdepth
+        if depth < mindepth:
+          continue
+      # match
+      if filename in files:
+        result.append(os.path.join(root, filename))
+        del dirs[:]
+  return result
+
+def usage():
+  sys.stderr.write("""Usage: %(progName)s [<options>] <dirlist> <filename>
+Options:
+   --mindepth=<mindepth>
+       Both behave in the same way as their find(1) equivalents.
+   --prune=<dirname>
+       Avoids returning results from inside any directory called <dirname>
+       (e.g., "*/out/*"). May be used multiple times.
+""" % {
+      "progName": os.path.split(sys.argv[0])[1],
+    })
+  sys.exit(1)
+
+def main(argv):
+  mindepth = -1
+  prune = []
+  i=1
+  while i<len(argv) and len(argv[i])>2 and argv[i][0:2] == "--":
+    arg = argv[i]
+    if arg.startswith("--mindepth="):
+      try:
+        mindepth = int(arg[len("--mindepth="):])
+      except ValueError:
+        usage()
+    elif arg.startswith("--prune="):
+      p = arg[len("--prune="):]
+      if len(p) == 0:
+        usage()
+      prune.append(p)
+    else:
+      usage()
+    i += 1
+  if len(argv)-i < 2: # need both <dirlist> and <filename>
+    usage()
+  dirlist = argv[i:-1]
+  filename = argv[-1]
+  results = perform_find(mindepth, prune, dirlist, filename)
+  results.sort()
+  for r in set(results):
+    print r
+
+if __name__ == "__main__":
+  main(sys.argv)
diff --git a/build/tools/fixlinebreaks.sh b/build/tools/fixlinebreaks.sh
new file mode 100644 (file)
index 0000000..85b7b60
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+#
+# Convert EOL convention on source files from CRLF to LF.
+#
+
+echo "Scanning..."
+FILES=`find . \( -iname '*.c' -o -iname '*.cpp' -o -iname '*.h' -o -iname '*.mk' -o -iname '*.html' -o -iname '*.css' \) -print`
+
+echo "Converting..."
+for file in $FILES ; do
+       echo $file
+       tr -d \\r < $file > _temp_file
+       mv _temp_file $file
+done
+exit 0
+
diff --git a/build/tools/fs_config/Android.mk b/build/tools/fs_config/Android.mk
new file mode 100644 (file)
index 0000000..3f2ed95
--- /dev/null
@@ -0,0 +1,27 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_SRC_FILES := fs_config.c
+LOCAL_MODULE := fs_config
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_MODULE_TAGS := eng
+
+include $(BUILD_HOST_EXECUTABLE)
+
+endif  # !TARGET_SIMULATOR
diff --git a/build/tools/fs_config/fs_config.c b/build/tools/fs_config/fs_config.c
new file mode 100644 (file)
index 0000000..5b99b30
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "private/android_filesystem_config.h"
+
+// This program takes a list of files and directories (indicated by a
+// trailing slash) on the stdin, and prints to stdout each input
+// filename along with its desired uid, gid, and mode (in octal).
+// The leading slash should be stripped from the input.
+//
+// Example input:
+//
+//    system/etc/dbus.conf
+//    data/app/
+//
+// Output:
+//
+//    system/etc/dbus.conf 1002 1002 440
+//    data/app 1000 1000 771
+//
+// Note that the output will omit the trailing slash from
+// directories.
+
+int main(int argc, char** argv) {
+  char buffer[1024];
+
+  while (fgets(buffer, 1023, stdin) != NULL) {
+    int is_dir = 0;
+    int i;
+    for (i = 0; i < 1024 && buffer[i]; ++i) {
+      switch (buffer[i]) {
+        case '\n':
+          buffer[i-is_dir] = '\0';
+          i = 1025;
+          break;
+        case '/':
+          is_dir = 1;
+          break;
+        default:
+          is_dir = 0;
+          break;
+      }
+    }
+
+    unsigned uid = 0, gid = 0, mode = 0;
+    fs_config(buffer, is_dir, &uid, &gid, &mode);
+    printf("%s %d %d %o\n", buffer, uid, gid, mode);
+  }
+  return 0;
+}
diff --git a/build/tools/fs_get_stats/Android.mk b/build/tools/fs_get_stats/Android.mk
new file mode 100644 (file)
index 0000000..c9b4a05
--- /dev/null
@@ -0,0 +1,9 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := fs_get_stats.c
+
+LOCAL_MODULE := fs_get_stats
+
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/build/tools/fs_get_stats/fs_get_stats.c b/build/tools/fs_get_stats/fs_get_stats.c
new file mode 100644 (file)
index 0000000..356f6f9
--- /dev/null
@@ -0,0 +1,64 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <private/android_filesystem_config.h>
+
+#define DO_DEBUG 1
+
+#define ERROR(fmt,args...) \
+       do { \
+               fprintf(stderr, "%s:%d: ERROR: " fmt,  \
+                       __FILE__, __LINE__, ##args);    \
+       } while (0)
+
+#if DO_DEBUG
+#define DEBUG(fmt,args...) \
+       do { fprintf(stderr, "DEBUG: " fmt, ##args); } while(0)
+#else
+#define DEBUG(x...)               do {} while(0)
+#endif
+
+void
+print_help(void)
+{
+       fprintf(stderr, "fs_get_stats: retrieve the target file stats "
+               "for the specified file\n");
+       fprintf(stderr, "usage: fs_get_stats cur_perms is_dir filename\n");
+       fprintf(stderr, "\tcur_perms - The current permissions of "
+               "the file\n");
+       fprintf(stderr, "\tis_dir    - Is filename is a dir, 1. Otherwise, 0.\n");
+       fprintf(stderr, "\tfilename  - The filename to lookup\n");
+       fprintf(stderr, "\n");
+}
+
+int
+main(int argc, const char *argv[])
+{
+       char *endptr;
+       char is_dir = 0;
+       unsigned perms = 0;
+       unsigned uid = (unsigned)-1;
+       unsigned gid = (unsigned)-1;
+
+       if (argc < 4) {
+               ERROR("Invalid arguments\n");
+               print_help();
+               exit(-1);
+       }
+
+       perms = (unsigned)strtoul(argv[1], &endptr, 0);
+       if (!endptr || (endptr == argv[1]) || (*endptr != '\0')) {
+               ERROR("current permissions must be a number. Got '%s'.\n", argv[1]);
+               exit(-1);
+       }
+
+       if (!strcmp(argv[2], "1"))
+               is_dir = 1;
+
+       fs_config(argv[3], is_dir, &uid, &gid, &perms);
+       fprintf(stdout, "%d %d 0%o\n", uid, gid, perms);
+
+       return 0;
+}
diff --git a/build/tools/iself/Android.mk b/build/tools/iself/Android.mk
new file mode 100644 (file)
index 0000000..49fabff
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2005 The Android Open Source Project
+#
+# Android.mk for iself
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS += -O2 -g
+LOCAL_CFLAGS += -fno-function-sections -fno-data-sections -fno-inline
+LOCAL_CFLAGS += -Wall -Wno-unused-function #-Werror
+LOCAL_CFLAGS += -DDEBUG
+
+LOCAL_C_INCLUDES:= \
+       $(LOCAL_PATH)/
+
+LOCAL_SRC_FILES := \
+       iself.c
+
+LOCAL_MODULE := iself
+
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/build/tools/iself/debug.h b/build/tools/iself/debug.h
new file mode 100644 (file)
index 0000000..9bbf47f
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#define unlikely(expr) __builtin_expect (expr, 0)
+#define likely(expr)   __builtin_expect (expr, 1)
+
+#ifdef DEBUG
+
+    #define FAILIF(cond, msg...) do {                        \
+       if (unlikely(cond)) {                                \
+        fprintf(stderr, "%s(%d): ", __FILE__, __LINE__); \
+               fprintf(stderr, ##msg);                          \
+               exit(1);                                         \
+       }                                                    \
+} while(0)
+
+/* Debug enabled */
+    #define ASSERT(x) do {                                \
+       if (unlikely(!(x))) {                             \
+               fprintf(stderr,                               \
+                               "ASSERTION FAILURE %s:%d: [%s]\n",    \
+                               __FILE__, __LINE__, #x);              \
+               exit(1);                                      \
+       }                                                 \
+} while(0)
+
+#else
+
+    #define FAILIF(cond, msg...) do { \
+       if (unlikely(cond)) {         \
+               fprintf(stderr, ##msg);   \
+               exit(1);                  \
+       }                             \
+} while(0)
+
+/* No debug */
+    #define ASSERT(x)   do { } while(0)
+
+#endif/* DEBUG */
+
+#define FAILIF_LIBELF(cond, function) \
+    FAILIF(cond, "%s(): %s\n", #function, elf_errmsg(elf_errno()));
+
+static inline void *MALLOC(unsigned int size) {
+    void *m = malloc(size);
+    FAILIF(NULL == m, "malloc(%d) failed!\n", size);
+    return m;
+}
+
+static inline void *CALLOC(unsigned int num_entries, unsigned int entry_size) {
+    void *m = calloc(num_entries, entry_size);
+    FAILIF(NULL == m, "calloc(%d, %d) failed!\n", num_entries, entry_size);
+    return m;
+}
+
+static inline void *REALLOC(void *ptr, unsigned int size) {
+    void *m = realloc(ptr, size);
+    FAILIF(NULL == m, "realloc(%p, %d) failed!\n", ptr, size);
+    return m;
+}
+
+static inline void FREE(void *ptr) {
+    free(ptr);
+}
+
+static inline void FREEIF(void *ptr) {
+    if (ptr) FREE(ptr);
+}
+
+#define PRINT(x...)  do {                             \
+    extern int quiet_flag;                            \
+    if(likely(!quiet_flag))                           \
+        fprintf(stdout, ##x);                         \
+} while(0)
+
+#define ERROR PRINT
+
+#define INFO(x...)  do {                              \
+    extern int verbose_flag;                          \
+    if(unlikely(verbose_flag))                        \
+        fprintf(stdout, ##x);                         \
+} while(0)
+
+/* Prints a hex and ASCII dump of the selected buffer to the selected stream. */
+int dump_hex_buffer(FILE *s, void *b, size_t l, size_t elsize);
+
+#endif/*DEBUG_H*/
diff --git a/build/tools/iself/iself.c b/build/tools/iself/iself.c
new file mode 100644 (file)
index 0000000..e634a22
--- /dev/null
@@ -0,0 +1,36 @@
+#include <debug.h>
+#include <unistd.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+int
+main(int argc, char **argv)
+{
+       char *fname;
+       int fd;
+       char magic[4];
+
+       argc--, argv++;
+       FAILIF(argc != 1, "Expecting a file name!\n");
+       fname = *argv;
+
+       fd = open(fname, O_RDONLY);
+       FAILIF(fd < 0, "Error opening %s for reading: %s (%d)!\n",
+           fname, strerror(errno), errno);
+
+       FAILIF(4 != read(fd, magic, 4),
+           "Could not read first 4 bytes from %s: %s (%d)!\n",
+           fname, strerror(errno), errno);
+
+    if (magic[0] != 0x7f) return 1;
+    if (magic[1] != 'E')  return 1;
+    if (magic[2] != 'L')  return 1;
+    if (magic[3] != 'F')  return 1;
+
+    return 0;
+}
diff --git a/build/tools/isprelinked/Android.mk b/build/tools/isprelinked/Android.mk
new file mode 100644 (file)
index 0000000..e085f29
--- /dev/null
@@ -0,0 +1,40 @@
+# Copyright 2005 The Android Open Source Project
+#
+# Android.mk for apriori 
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+ifeq ($(TARGET_ARCH),arm)
+include $(CLEAR_VARS)
+
+LOCAL_LDLIBS += -ldl
+LOCAL_CFLAGS += -O2 -g 
+LOCAL_CFLAGS += -fno-function-sections -fno-data-sections -fno-inline 
+LOCAL_CFLAGS += -Wall -Wno-unused-function #-Werror
+LOCAL_CFLAGS += -DSUPPORT_ANDROID_PRELINK_TAGS
+LOCAL_CFLAGS += -DARM_SPECIFIC_HACKS
+LOCAL_CFLAGS += -DDEBUG
+
+ifeq ($(HOST_OS),windows)
+LOCAL_LDLIBS += -lintl
+endif
+
+LOCAL_SRC_FILES := \
+       isprelinked.c \
+       debug.c \
+       prelink_info.c
+
+LOCAL_C_INCLUDES:= \
+       $(LOCAL_PATH)/ \
+       external/elfutils/lib/ \
+       external/elfutils/libelf/ \
+       external/elfutils/libebl/ \
+       external/elfcopy/
+
+LOCAL_STATIC_LIBRARIES := libelfcopy libelf libebl libebl_arm #dl
+
+LOCAL_MODULE := isprelinked
+
+include $(BUILD_HOST_EXECUTABLE)
+endif #TARGET_ARCH==arm
diff --git a/build/tools/isprelinked/common.h b/build/tools/isprelinked/common.h
new file mode 100644 (file)
index 0000000..f5d9d2e
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <libelf.h>
+#include <elf.h>
+
+#define unlikely(expr) __builtin_expect (expr, 0)
+#define likely(expr)   __builtin_expect (expr, 1)
+
+#define MIN(a,b) ((a)<(b)?(a):(b)) /* no side effects in arguments allowed! */
+
+static inline int is_host_little(void)
+{
+    short val = 0x10;
+    return ((char *)&val)[0] != 0;
+}
+
+static inline long switch_endianness(long val)
+{
+       long newval;
+       ((char *)&newval)[3] = ((char *)&val)[0];
+       ((char *)&newval)[2] = ((char *)&val)[1];
+       ((char *)&newval)[1] = ((char *)&val)[2];
+       ((char *)&newval)[0] = ((char *)&val)[3];
+       return newval;
+}
+
+#endif/*COMMON_H*/
diff --git a/build/tools/isprelinked/debug.c b/build/tools/isprelinked/debug.c
new file mode 100644 (file)
index 0000000..6066543
--- /dev/null
@@ -0,0 +1,37 @@
+#include <debug.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#define NUM_COLS  (32)
+
+int dump_hex_buffer(FILE *s, void *b, size_t len, size_t elsize) {
+    int num_nonprintable = 0;
+    int i, last;
+    char *pchr = (char *)b;
+    fputc('\n', s);
+    for (i = last = 0; i < len; i++) {
+        if (!elsize) {
+            if (i && !(i % 4)) fprintf(s, " ");
+            if (i && !(i % 8)) fprintf(s, " ");
+        } else {
+            if (i && !(i % elsize)) fprintf(s, " ");
+        }
+
+        if (i && !(i % NUM_COLS)) {
+            while (last < i) {
+                if (isprint(pchr[last]))
+                    fputc(pchr[last], s);
+                else {
+                    fputc('.', s); 
+                    num_nonprintable++;
+                }
+                last++;
+            }
+            fprintf(s, " (%d)\n", i);
+        }
+        fprintf(s, "%02x", (unsigned char)pchr[i]);
+    }
+    if (i && (i % NUM_COLS)) fputs("\n", s);
+    return num_nonprintable;
+}
+
diff --git a/build/tools/isprelinked/debug.h b/build/tools/isprelinked/debug.h
new file mode 100644 (file)
index 0000000..3996898
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <common.h>
+
+#ifdef DEBUG
+
+    #define FAILIF(cond, msg...) do {                        \
+       if (unlikely(cond)) {                                \
+        fprintf(stderr, "%s(%d): ", __FILE__, __LINE__); \
+               fprintf(stderr, ##msg);                          \
+               exit(1);                                         \
+       }                                                    \
+} while(0)
+
+/* Debug enabled */
+    #define ASSERT(x) do {                                \
+       if (unlikely(!(x))) {                             \
+               fprintf(stderr,                               \
+                               "ASSERTION FAILURE %s:%d: [%s]\n",    \
+                               __FILE__, __LINE__, #x);              \
+               exit(1);                                      \
+       }                                                 \
+} while(0)
+
+#else
+
+    #define FAILIF(cond, msg...) do { \
+       if (unlikely(cond)) {         \
+               fprintf(stderr, ##msg);   \
+               exit(1);                  \
+       }                             \
+} while(0)
+
+/* No debug */
+    #define ASSERT(x)   do { } while(0)
+
+#endif/* DEBUG */
+
+#define FAILIF_LIBELF(cond, function) \
+    FAILIF(cond, "%s(): %s\n", #function, elf_errmsg(elf_errno()));
+
+static inline void *MALLOC(unsigned int size) {
+    void *m = malloc(size);
+    FAILIF(NULL == m, "malloc(%d) failed!\n", size);
+    return m;
+}
+
+static inline void *CALLOC(unsigned int num_entries, unsigned int entry_size) {
+    void *m = calloc(num_entries, entry_size);
+    FAILIF(NULL == m, "calloc(%d, %d) failed!\n", num_entries, entry_size);
+    return m;
+}
+
+static inline void *REALLOC(void *ptr, unsigned int size) {
+    void *m = realloc(ptr, size);
+    FAILIF(NULL == m, "realloc(%p, %d) failed!\n", ptr, size);
+    return m;
+}
+
+static inline void FREE(void *ptr) {
+    free(ptr);
+}
+
+static inline void FREEIF(void *ptr) {
+    if (ptr) FREE(ptr);
+}
+
+#define PRINT(x...)  do {                             \
+    extern int quiet_flag;                            \
+    if(likely(!quiet_flag))                           \
+        fprintf(stdout, ##x);                         \
+} while(0)
+
+#define ERROR PRINT
+
+#define INFO(x...)  do {                              \
+    extern int verbose_flag;                          \
+    if(unlikely(verbose_flag))                        \
+        fprintf(stdout, ##x);                         \
+} while(0)
+
+/* Prints a hex and ASCII dump of the selected buffer to the selected stream. */
+int dump_hex_buffer(FILE *s, void *b, size_t l, size_t elsize);
+
+#endif/*DEBUG_H*/
diff --git a/build/tools/isprelinked/isprelinked.c b/build/tools/isprelinked/isprelinked.c
new file mode 100644 (file)
index 0000000..c677e39
--- /dev/null
@@ -0,0 +1,89 @@
+/* TODO:
+   1. check the ARM EABI version--this works for versions 1 and 2.
+   2. use a more-intelligent approach to finding the symbol table, symbol-string
+      table, and the .dynamic section.
+   3. fix the determination of the host and ELF-file endianness
+   4. write the help screen
+*/
+
+#include <stdio.h>
+#include <common.h>
+#include <debug.h>
+#include <libelf.h>
+#include <libebl.h>
+#ifdef ARM_SPECIFIC_HACKS
+    #include <libebl_arm.h>
+#endif/*ARM_SPECIFIC_HACKS*/
+#include <elf.h>
+#include <gelf.h>
+#include <string.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <rangesort.h>
+#include <prelink_info.h>
+#include <libgen.h>
+
+
+/* Flag set by --verbose.  This variable is global as it is accessed by the
+   macro INFO() in multiple compilation unites. */
+int verbose_flag = 0;
+/* Flag set by --quiet.  This variable is global as it is accessed by the
+   macro PRINT() in multiple compilation unites. */
+int quiet_flag = 0;
+
+int main(int argc, char **argv) {
+
+    argc--, argv++;
+    if (!argc)
+        return 0;
+
+    /* Check to see whether the ELF library is current. */
+    FAILIF (elf_version(EV_CURRENT) == EV_NONE, "libelf is out of date!\n");
+
+    const char *filename;
+    for (; argc; argc--) {
+        filename = *argv++;
+
+        Elf *elf;
+        GElf_Ehdr elf_hdr;
+        int fd; 
+        int prelinked;
+        long prelink_addr = 0;
+
+        INFO("Processing file [%s]\n", filename);
+
+        fd = open(filename, O_RDONLY);
+        FAILIF(fd < 0, "open(%d): %s (%d).\n", 
+               filename,
+               strerror(errno),
+               errno);
+
+        elf = elf_begin(fd, ELF_C_READ_MMAP_PRIVATE, NULL);
+        FAILIF_LIBELF(elf == NULL, elf_begin);
+
+        FAILIF_LIBELF(0 == gelf_getehdr(elf, &elf_hdr), 
+                      gelf_getehdr);
+
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+        prelinked = check_prelinked(filename, elf_hdr.e_ident[EI_DATA] == ELFDATA2LSB, 
+                                    &prelink_addr);
+#else
+        #error 'SUPPORT_ANDROID_PRELINK_TAGS is not defined!'
+#endif
+
+        if (prelinked)
+            PRINT("%s: 0x%08x\n", filename, prelink_addr);
+        else
+            PRINT("%s: not prelinked\n", filename);
+
+        FAILIF_LIBELF(elf_end(elf), elf_end);
+        close(fd);
+    }
+    
+    return 0;
+} 
+
diff --git a/build/tools/isprelinked/prelink_info.c b/build/tools/isprelinked/prelink_info.c
new file mode 100644 (file)
index 0000000..21b1519
--- /dev/null
@@ -0,0 +1,71 @@
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <prelink_info.h>
+#include <debug.h>
+#include <common.h>
+
+typedef struct {
+       long mmap_addr;
+       char tag[4]; /* 'P', 'R', 'E', ' ' */
+} prelink_info_t __attribute__((packed));
+
+static inline void set_prelink(long *prelink_addr, 
+                                                          int elf_little,
+                                                          prelink_info_t *info)
+{
+    FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %d!\n", sizeof(prelink_info_t));
+       if (prelink_addr) {
+               if (!(elf_little ^ is_host_little())) {
+                       /* Same endianness */
+                       *prelink_addr = info->mmap_addr;
+               }
+               else {
+                       /* Different endianness */
+                       *prelink_addr = switch_endianness(info->mmap_addr);
+               }
+       }
+}
+
+int check_prelinked(const char *fname, int elf_little, long *prelink_addr)
+{
+    FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %d!\n", sizeof(prelink_info_t));
+       int fd = open(fname, O_RDONLY);
+       FAILIF(fd < 0, "open(%s, O_RDONLY): %s (%d)!\n",
+                  fname, strerror(errno), errno);
+       off_t end = lseek(fd, 0, SEEK_END);
+
+    int nr = sizeof(prelink_info_t);
+
+    off_t sz = lseek(fd, -nr, SEEK_CUR);
+       ASSERT((long)(end - sz) == (long)nr);
+       FAILIF(sz == (off_t)-1, 
+                  "lseek(%d, 0, SEEK_END): %s (%d)!\n", 
+                  fd, strerror(errno), errno);
+
+       prelink_info_t info;
+       int num_read = read(fd, &info, nr);
+       FAILIF(num_read < 0, 
+                  "read(%d, &info, sizeof(prelink_info_t)): %s (%d)!\n",
+                  fd, strerror(errno), errno);
+       FAILIF(num_read != sizeof(info),
+                  "read(%d, &info, sizeof(prelink_info_t)): did not read %d bytes as "
+                  "expected (read %d)!\n",
+                  fd, sizeof(info), num_read);
+
+       int prelinked = 0;
+       if (!strncmp(info.tag, "PRE ", 4)) {
+               set_prelink(prelink_addr, elf_little, &info);
+               prelinked = 1;
+       }
+       FAILIF(close(fd) < 0, "close(%d): %s (%d)!\n", fd, strerror(errno), errno);
+       return prelinked;
+}
+
+#endif /*SUPPORT_ANDROID_PRELINK_TAGS*/
diff --git a/build/tools/isprelinked/prelink_info.h b/build/tools/isprelinked/prelink_info.h
new file mode 100644 (file)
index 0000000..afc03e9
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef PRELINK_INFO_H
+#define PRELINK_INFO_H
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+
+int check_prelinked(const char *fname, int elf_little, long *prelink_addr);
+
+#endif
+#endif/*PRELINK_INFO_H*/
diff --git a/build/tools/java-event-log-tags.py b/build/tools/java-event-log-tags.py
new file mode 100644 (file)
index 0000000..c63fa20
--- /dev/null
@@ -0,0 +1,147 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Usage: java-event-log-tags.py [-o output_file] <input_file> <merged_tags_file>
+
+Generate a java class containing constants for each of the event log
+tags in the given input file.
+
+-h to display this usage message and exit.
+"""
+
+import cStringIO
+import getopt
+import os
+import re
+import sys
+
+import event_log_tags
+
+output_file = None
+
+try:
+  opts, args = getopt.getopt(sys.argv[1:], "ho:")
+except getopt.GetoptError, err:
+  print str(err)
+  print __doc__
+  sys.exit(2)
+
+for o, a in opts:
+  if o == "-h":
+    print __doc__
+    sys.exit(2)
+  elif o == "-o":
+    output_file = a
+  else:
+    print >> sys.stderr, "unhandled option %s" % (o,)
+    sys.exit(1)
+
+if len(args) != 2:
+  print "need exactly two input files, not %d" % (len(args),)
+  print __doc__
+  sys.exit(1)
+
+fn = args[0]
+tagfile = event_log_tags.TagFile(fn)
+
+# Load the merged tag file (which should have numbers assigned for all
+# tags.  Use the numbers from the merged file to fill in any missing
+# numbers from the input file.
+merged_fn = args[1]
+merged_tagfile = event_log_tags.TagFile(merged_fn)
+merged_by_name = dict([(t.tagname, t) for t in merged_tagfile.tags])
+for t in tagfile.tags:
+  if t.tagnum is None:
+    if t.tagname in merged_by_name:
+      t.tagnum = merged_by_name[t.tagname].tagnum
+    else:
+      # We're building something that's not being included in the
+      # product, so its tags don't appear in the merged file.  Assign
+      # them all an arbitrary number so we can emit the java and
+      # compile the (unused) package.
+      t.tagnum = 999999
+
+if "java_package" not in tagfile.options:
+  tagfile.AddError("java_package option not specified", linenum=0)
+
+hide = True
+if "javadoc_hide" in tagfile.options:
+  hide = event_log_tags.BooleanFromString(tagfile.options["javadoc_hide"][0])
+
+if tagfile.errors:
+  for fn, ln, msg in tagfile.errors:
+    print >> sys.stderr, "%s:%d: error: %s" % (fn, ln, msg)
+  sys.exit(1)
+
+buffer = cStringIO.StringIO()
+buffer.write("/* This file is auto-generated.  DO NOT MODIFY.\n"
+             " * Source file: %s\n"
+             " */\n\n" % (fn,))
+
+buffer.write("package %s;\n\n" % (tagfile.options["java_package"][0],))
+
+basename, _ = os.path.splitext(os.path.basename(fn))
+
+if hide:
+  buffer.write("/**\n"
+               " * @hide\n"
+               " */\n")
+buffer.write("public class %s {\n" % (basename,))
+buffer.write("  private %s() { }  // don't instantiate\n" % (basename,))
+
+for t in tagfile.tags:
+  if t.description:
+    buffer.write("\n  /** %d %s %s */\n" % (t.tagnum, t.tagname, t.description))
+  else:
+    buffer.write("\n  /** %d %s */\n" % (t.tagnum, t.tagname))
+
+  buffer.write("  public static final int %s = %d;\n" %
+               (t.tagname.upper(), t.tagnum))
+
+keywords = frozenset(["abstract", "continue", "for", "new", "switch", "assert",
+                      "default", "goto", "package", "synchronized", "boolean",
+                      "do", "if", "private", "this", "break", "double",
+                      "implements", "protected", "throw", "byte", "else",
+                      "import", "public", "throws", "case", "enum",
+                      "instanceof", "return", "transient", "catch", "extends",
+                      "int", "short", "try", "char", "final", "interface",
+                      "static", "void", "class", "finally", "long", "strictfp",
+                      "volatile", "const", "float", "native", "super", "while"])
+
+def javaName(name):
+  out = name[0].lower() + re.sub(r"[^A-Za-z0-9]", "", name.title())[1:]
+  if out in keywords:
+    out += "_"
+  return out
+
+javaTypes = ["ERROR", "int", "long", "String", "Object[]"]
+for t in tagfile.tags:
+  methodName = javaName("write_" + t.tagname)
+  if t.description:
+    args = [arg.strip("() ").split("|") for arg in t.description.split(",")]
+  else:
+    args = []
+  argTypesNames = ", ".join([javaTypes[int(arg[1])] + " " + javaName(arg[0]) for arg in args])
+  argNames = "".join([", " + javaName(arg[0]) for arg in args])
+  buffer.write("\n  public static void %s(%s) {" % (methodName, argTypesNames))
+  buffer.write("\n    android.util.EventLog.writeEvent(%s%s);" % (t.tagname.upper(), argNames))
+  buffer.write("\n  }\n")
+
+
+buffer.write("}\n");
+
+event_log_tags.WriteOutput(output_file, buffer)
diff --git a/build/tools/kcm/Android.mk b/build/tools/kcm/Android.mk
new file mode 100644 (file)
index 0000000..130a13a
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright 2007 The Android Open Source Project
+#
+# Copies files into the directory structure described by a manifest
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+       kcm.cpp
+
+LOCAL_MODULE := kcm
+
+include $(BUILD_HOST_EXECUTABLE)
+
+
diff --git a/build/tools/kcm/kcm.cpp b/build/tools/kcm/kcm.cpp
new file mode 100644 (file)
index 0000000..23ac377
--- /dev/null
@@ -0,0 +1,421 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ui/KeycodeLabels.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <map>
+#include <string>
+#include <utils/ByteOrder.h>
+
+using namespace std;
+
+enum {
+    LENDIAN,
+    BENDIAN
+};
+
+/*
+ * 1: KeyEvent name
+ * 2: display_label
+ * 3: number
+ * 4..7: base, shift, alt, shift-alt
+ */
+#define COLUMNS (3+4)
+
+struct KeyRecord
+{
+    int lineno;
+    int values[COLUMNS];
+};
+
+struct PropValue
+{
+    PropValue() { lineno = -1; }
+    PropValue(const PropValue& that) { lineno=that.lineno; value=that.value; }
+    PropValue(int l, const string& v) { lineno = l; value = v; }
+
+    int lineno;
+    string value;
+};
+
+static int usage();
+
+//  0 -- ok
+// >0 -- error
+static int parse_key_line(const char* filename, int lineno, char* line,
+        KeyRecord* out);
+static int write_kr(int fd, const KeyRecord& kr);
+
+int g_endian;
+
+int
+main(int argc, char** argv)
+{
+    int err;
+    if (argc != 3) {
+        return usage();
+    }
+
+    const char* filename = argv[1];
+    const char* outfilename = argv[2];
+
+    int in = open(filename, O_RDONLY);
+    if (in == -1) {
+        fprintf(stderr, "kcm: error opening file for read: %s\n", filename);
+        return 1;
+    }
+
+    off_t size = lseek(in, 0, SEEK_END);
+    lseek(in, 0, SEEK_SET);
+
+    char* input = (char*)malloc(size+1);
+    read(in, input, size);
+    input[size] = '\0';
+
+    close(in);
+    in = -1;
+
+    map<string,PropValue> properties;
+    map<int,KeyRecord> keys;
+    int errorcount = 0;
+    int lineno = 1;
+    char *thisline = input;
+    while (*thisline) {
+        KeyRecord kr;
+        char *nextline = thisline;
+        
+        while (*nextline != '\0' && *nextline != '\n' && *nextline != '\r') {
+            nextline++;
+        }
+
+        // eat whitespace, but not newlines
+        while (*thisline != '\0' && (*thisline == ' ' || *thisline == '\t')) {
+            thisline++;
+        }
+
+        // find the end of the line
+        char lineend = *nextline;
+        *nextline = '\0';
+        if (lineend == '\r' && nextline[1] == '\n') {
+            nextline++;
+        }
+
+        if (*thisline == '\0' || *thisline == '\r' || *thisline == '\n'
+                 || *thisline == '#') {
+            // comment or blank line
+        }
+        else if (*thisline == '[') {
+            // property - syntax [name=value]
+            // look for =
+            char* prop = thisline+1;
+            char* end = prop;
+            while (*end != '\0' && *end != '=') {
+                end++;
+            }
+            if (*end != '=') {
+                fprintf(stderr, "%s:%d: invalid property line: %s\n",
+                        filename, lineno, thisline);
+                errorcount++;
+            } else {
+                *end = '\0';
+                char* value = end+1;
+                end = nextline;
+                while (end > prop && *end != ']') {
+                    end--;
+                }
+                if (*end != ']') {
+                    fprintf(stderr, "%s:%d: property missing closing ]: %s\n",
+                            filename, lineno, thisline);
+                    errorcount++;
+                } else {
+                    *end = '\0';
+                    properties[prop] = PropValue(lineno, value);
+                }
+            }
+        }
+        else {
+            // key
+            err = parse_key_line(filename, lineno, thisline, &kr);
+            if (err == 0) {
+                kr.lineno = lineno;
+
+                map<int,KeyRecord>::iterator old = keys.find(kr.values[0]);
+                if (old != keys.end()) {
+                    fprintf(stderr, "%s:%d: keycode %d already defined\n",
+                            filename, lineno, kr.values[0]);
+                    fprintf(stderr, "%s:%d: previously defined here\n",
+                            filename, old->second.lineno);
+                    errorcount++;
+                }
+
+                keys[kr.values[0]] = kr;
+            }
+            else if (err > 0) {
+                errorcount += err;
+            }
+        }
+        lineno++;
+
+        nextline++;
+        thisline = nextline;
+
+        if (errorcount > 20) {
+            fprintf(stderr, "%s:%d: too many errors.  stopping.\n", filename,
+                    lineno);
+            return 1;
+        }
+    }
+
+    free(input);
+
+    map<string,PropValue>::iterator sit = properties.find("type");
+    if (sit == properties.end()) {
+        fprintf(stderr, "%s: key character map must contain type property.\n",
+               argv[0]);
+        errorcount++;
+    }
+    PropValue pv = sit->second;
+    unsigned char kbdtype = 0;
+    if (pv.value == "NUMERIC") {
+        kbdtype = 1;
+    }
+    else if (pv.value == "Q14") {
+        kbdtype = 2;
+    }
+    else if (pv.value == "QWERTY") {
+        kbdtype = 3;
+    }
+    else {
+        fprintf(stderr, "%s:%d: keyboard type must be one of NUMERIC, Q14 "
+                " or QWERTY, not %s\n", filename, pv.lineno, pv.value.c_str());
+    }
+
+    if (errorcount != 0) {
+        return 1;
+    }
+
+    int out = open(outfilename, O_RDWR|O_CREAT|O_TRUNC, 0664);
+    if (out == -1) {
+        fprintf(stderr, "kcm: error opening file for write: %s\n", outfilename);
+        return 1;
+    }
+
+    int count = keys.size();
+    
+    map<int,KeyRecord>::iterator it;
+    int n;
+
+    /**
+     * File Format:
+     *    Offset    Description     Value
+     *    0         magic string    "keychar"
+     *    8         endian marker   0x12345678
+     *    12        version         0x00000002
+     *    16        key count       number of key entries
+     *    20        keyboard type   NUMERIC, Q14, QWERTY, etc.
+     *    21        padding         0
+     *    32        the keys
+     */
+    err = write(out, "keychar", 8);
+    if (err == -1) goto bad_write;
+
+    n = htodl(0x12345678);
+    err = write(out, &n, 4);
+    if (err == -1) goto bad_write;
+
+    n = htodl(0x00000002);
+    err = write(out, &n, 4);
+    if (err == -1) goto bad_write;
+
+    n = htodl(count);
+    err = write(out, &n, 4);
+    if (err == -1) goto bad_write;
+
+    err = write(out, &kbdtype, 1);
+    if (err == -1) goto bad_write;
+
+    char zero[11];
+    memset(zero, 0, 11);
+    err = write(out, zero, 11);
+    if (err == -1) goto bad_write;
+
+    for (it = keys.begin(); it != keys.end(); it++) {
+        const KeyRecord& kr = it->second;
+        /*
+        printf("%2d/ [%d] [%d] [%d] [%d] [%d] [%d] [%d]\n", kr.lineno,
+                kr.values[0], kr.values[1], kr.values[2], kr.values[3],
+                kr.values[4], kr.values[5], kr.values[6]);
+        */
+        err = write_kr(out, kr);
+        if (err == -1) goto bad_write;
+    }
+
+    close(out);
+    return 0;
+
+bad_write:
+    fprintf(stderr, "kcm: fatal error writing to file: %s\n", outfilename);
+    close(out);
+    unlink(outfilename);
+    return 1;
+}
+
+static int usage()
+{
+    fprintf(stderr,
+            "usage: kcm INPUT OUTPUT\n"
+            "\n"
+            "INPUT   keycharmap file\n"
+            "OUTPUT  compiled keycharmap file\n"
+        );
+    return 1;
+}
+
+static int
+is_whitespace(const char* p)
+{
+    while (*p) {
+        if (!isspace(*p)) {
+            return 0;
+        }
+        p++;
+    }
+    return 1;
+}
+
+
+static int
+parse_keycode(const char* filename, int lineno, char* str, int* value)
+{
+    const KeycodeLabel *list = KEYCODES;
+    while (list->literal) {
+        if (0 == strcmp(str, list->literal)) {
+            *value = list->value;
+            return 0;
+        }
+        list++;
+    }
+
+    char* endptr;
+    *value = strtol(str, &endptr, 0);
+    if (*endptr != '\0') {
+        fprintf(stderr, "%s:%d: expected keycode label or number near: "
+                "%s\n", filename, lineno, str);
+        return 1;
+    }
+
+    if (*value == 0) {
+        fprintf(stderr, "%s:%d: 0 is not a valid keycode.\n",
+                filename, lineno);
+        return 1;
+    }
+
+    return 0;
+}
+
+static int
+parse_number(const char* filename, int lineno, char* str, int* value)
+{
+    int len = strlen(str);
+
+    if (len == 3 && str[0] == '\'' && str[2] == '\'') {
+        if (str[1] > 0 && str[1] < 127) {
+            *value = (int)str[1];
+            return 0;
+        } else {
+            fprintf(stderr, "%s:%d: only low ascii characters are allowed in"
+                    " quotes near: %s\n", filename, lineno, str);
+            return 1;
+        }
+    }
+
+    char* endptr;
+    *value = strtol(str, &endptr, 0);
+    if (*endptr != '\0') {
+        fprintf(stderr, "%s:%d: expected number or quoted ascii but got: %s\n",
+                filename, lineno, str);
+        return 1;
+    }
+
+    if (*value >= 0xfffe || *value < 0) {
+        fprintf(stderr, "%s:%d: unicode char out of range (no negatives, "
+                "nothing larger than 0xfffe): %s\n", filename, lineno, str);
+        return 1;
+    }
+
+    return 0;
+}
+
+static int
+parse_key_line(const char* filename, int lineno, char* line, KeyRecord* out)
+{
+    char* p = line;
+
+    int len = strlen(line);
+    char* s[COLUMNS];
+    for (int i=0; i<COLUMNS; i++) {
+        s[i] = (char*)malloc(len+1);
+    }
+
+    for (int i = 0; i < COLUMNS; i++) {
+        while (*p != '\0' && isspace(*p)) {
+            p++;
+        }
+
+        if (*p == '\0') {
+            fprintf(stderr, "%s:%d: not enough on this line: %s\n", filename,
+                    lineno, line);
+            return 1;
+        }
+
+        char *p1 = p;
+        while (*p != '\0' && !isspace(*p)) {
+            p++;
+        }
+
+        memcpy(s[i], p1, p - p1);
+        s[i][p - p1] = '\0';
+    }
+
+    while (*p != '\0' && isspace(*p)) {
+        *p++;
+    }
+    if (*p != '\0') {
+        fprintf(stderr, "%s:%d: too much on one line near: %s\n", filename,
+                lineno, p);
+        fprintf(stderr, "%s:%d: -->%s<--\n", filename, lineno, line);
+        return 1;
+    }
+
+    int errorcount = parse_keycode(filename, lineno, s[0], &out->values[0]);
+    for (int i=1; i<COLUMNS && errorcount == 0; i++) {
+        errorcount += parse_number(filename, lineno, s[i], &out->values[i]);
+    }
+
+    return errorcount;
+}
+
+struct WrittenRecord
+{
+    unsigned int keycode;       // 4 bytes
+    unsigned short values[COLUMNS - 1];   // 6*2 bytes = 12
+                                // 16 bytes total 
+};
+
+static int
+write_kr(int fd, const KeyRecord& kr)
+{
+    WrittenRecord wr;
+
+    wr.keycode = htodl(kr.values[0]);
+    for (int i=0; i<COLUMNS - 1; i++) {
+        wr.values[i] = htods(kr.values[i+1]);
+    }
+
+    return write(fd, &wr, sizeof(WrittenRecord));
+}
+
diff --git a/build/tools/lsd/Android.mk b/build/tools/lsd/Android.mk
new file mode 100644 (file)
index 0000000..a224741
--- /dev/null
@@ -0,0 +1,43 @@
+# Copyright 2005 The Android Open Source Project
+#
+# Android.mk for lsd 
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+ifeq ($(TARGET_ARCH),arm)
+include $(CLEAR_VARS)
+
+LOCAL_LDLIBS += -ldl
+LOCAL_CFLAGS += -O2 -g 
+LOCAL_CFLAGS += -fno-function-sections -fno-data-sections -fno-inline 
+LOCAL_CFLAGS += -Wall -Wno-unused-function #-Werror
+LOCAL_CFLAGS += -DBIG_ENDIAN=1
+LOCAL_CFLAGS += -DARM_SPECIFIC_HACKS
+LOCAL_CFLAGS += -DSUPPORT_ANDROID_PRELINK_TAGS
+LOCAL_CFLAGS += -DDEBUG
+
+ifeq ($(HOST_OS),windows)
+LOCAL_LDLIBS += -lintl
+endif
+
+LOCAL_SRC_FILES := \
+        cmdline.c \
+        debug.c \
+        hash.c \
+        lsd.c \
+        main.c
+
+LOCAL_C_INCLUDES:= \
+       $(LOCAL_PATH)/ \
+       external/elfutils/lib/ \
+       external/elfutils/libelf/ \
+       external/elfutils/libebl/
+
+LOCAL_STATIC_LIBRARIES := libelf libebl libebl_arm #dl
+
+LOCAL_MODULE := lsd
+
+include $(BUILD_HOST_EXECUTABLE)
+endif #TARGET_ARCH==arm
+
diff --git a/build/tools/lsd/cmdline.c b/build/tools/lsd/cmdline.c
new file mode 100644 (file)
index 0000000..a3445cd
--- /dev/null
@@ -0,0 +1,130 @@
+#include <debug.h>
+#include <cmdline.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <ctype.h>
+
+extern char *optarg;
+extern int optind, opterr, optopt;
+
+static struct option long_options[] = {
+       {"verbose", no_argument, 0, 'V'},
+       {"help", no_argument, 0, 'h'},
+       {"print-info", no_argument, 0, 'p'},
+       {"list-needed-libs", no_argument, 0, 'n'},
+       {"lookup",     required_argument, 0, 'L'},
+       {0, 0, 0, 0},
+};
+
+/* This array must parallel long_options[] */
+static const char *descriptions[] = {
+       "print verbose output",
+       "print help screen",
+       "for each file, generate a listing of all dependencies that each symbol "
+            "satisfies",
+       "print out a list of needed libraries",
+       "provide a directory for library lookup"
+};
+
+void print_help(void)
+{
+    fprintf(stdout, 
+                       "invokation:\n"
+                       "\tlsd file1 [file2 file3 ... fileN] [-Ldir1 -Ldir2 ... -LdirN] "
+                       "[-Vpn]\n"
+                       "or\n"
+                       "\tlsd -h\n\n");
+       fprintf(stdout, "options:\n");
+       struct option *opt = long_options;
+       const char **desc = descriptions;
+       while (opt->name) {
+               fprintf(stdout, "\t-%c\n"
+                                               "\t--%-15s: %s\n",
+                               opt->val,
+                               opt->name,
+                               *desc);
+               opt++;
+               desc++;
+       }
+}
+
+int get_options(int argc, char **argv,
+                               int *list_needed_libs,
+                               int *info,
+                char ***dirs,
+                int *num_dirs,
+                int *verbose)
+{
+    int c;
+
+       ASSERT(list_needed_libs);
+       *list_needed_libs = 0;
+       ASSERT(info);
+       *info = 0;
+    ASSERT(verbose);
+    *verbose = 0;
+    ASSERT(dirs);
+       *dirs = NULL;
+    ASSERT(num_dirs);
+    int size = 0;
+    *num_dirs = 0;
+
+    while (1) {
+        /* getopt_long stores the option index here. */
+        int option_index = 0;
+
+        c = getopt_long (argc, argv, 
+                         "VhpnL:",
+                         long_options, 
+                         &option_index);
+        /* Detect the end of the options. */
+        if (c == -1) break;
+
+        if (isgraph(c)) {
+            INFO ("option -%c with value `%s'\n", c, (optarg ?: "(null)"));
+        }
+
+#define SET_STRING_OPTION(name) do { \
+    ASSERT(optarg);                  \
+    (*name) = strdup(optarg);        \
+} while(0)
+
+        switch (c) {
+        case 0:
+            /* If this option set a flag, do nothing else now. */
+            if (long_options[option_index].flag != 0)
+                break;
+            INFO ("option %s", long_options[option_index].name);
+            if (optarg)
+                INFO (" with arg %s", optarg);
+            INFO ("\n");
+            break;
+        case 'h': print_help(); exit(1); break;
+               case 'V': *verbose = 1; break;
+               case 'p': *info = 1; break;
+               case 'n': *list_needed_libs = 1; break;
+        case 'L': 
+            {
+                if (*num_dirs == size) {
+                    size += 10;
+                    *dirs = (char **)REALLOC(*dirs, size * sizeof(char *));
+                }
+                SET_STRING_OPTION(((*dirs) + *num_dirs));
+                (*num_dirs)++;
+            }
+                       break;
+        case '?':
+            /* getopt_long already printed an error message. */
+            break;
+
+#undef SET_STRING_OPTION
+
+        default:
+            FAILIF(1, "Unknown option");
+        }
+    }
+
+    return optind;
+}
diff --git a/build/tools/lsd/cmdline.h b/build/tools/lsd/cmdline.h
new file mode 100644 (file)
index 0000000..fc3be3e
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef CMDLINE_H
+#define CMDLINE_H
+
+void print_help(void);
+
+int get_options(int argc, char **argv,
+                               int *list_needed_libs,
+                               int *info,
+                char ***dirs,
+                int *num_dirs,
+                int *verbose);
+
+#endif/*CMDLINE_H*/
diff --git a/build/tools/lsd/common.h b/build/tools/lsd/common.h
new file mode 100644 (file)
index 0000000..6447b10
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <libelf.h>
+#include <elf.h>
+
+#define unlikely(expr) __builtin_expect (expr, 0)
+#define likely(expr)   __builtin_expect (expr, 1)
+
+#define MIN(a,b) ((a)<(b)?(a):(b)) /* no side effects in arguments allowed! */
+
+#endif/*COMMON_H*/
diff --git a/build/tools/lsd/debug.c b/build/tools/lsd/debug.c
new file mode 100644 (file)
index 0000000..54b18df
--- /dev/null
@@ -0,0 +1,39 @@
+#include <debug.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#define NUM_COLS  (32)
+
+int dump_hex_buffer(FILE *s, void *b, size_t len, size_t elsize)
+{
+    int num_nonprintable = 0;
+    int i, last;
+    char *pchr = (char *)b;
+    fputc('\n', s);
+    for (i = last = 0; i < len; i++) {
+        if (!elsize) {
+            if (i && !(i % 4)) fprintf(s, " ");
+            if (i && !(i % 8)) fprintf(s, " ");
+        }
+        else {
+            if (i && !(i % elsize)) fprintf(s, " ");
+        }
+
+        if (i && !(i % NUM_COLS)) {
+            while (last < i) {
+                if (isprint(pchr[last]))
+                    fputc(pchr[last], s); 
+                else {
+                    fputc('.', s); 
+                    num_nonprintable++;
+                }
+                last++;
+            }
+            fprintf(s, " (%d)\n", i);
+        }
+        fprintf(s, "%02x", (unsigned char)pchr[i]);
+    }
+    if (i && (i % NUM_COLS)) fputs("\n", s);
+    return num_nonprintable;
+}
+
diff --git a/build/tools/lsd/debug.h b/build/tools/lsd/debug.h
new file mode 100644 (file)
index 0000000..f7842f8
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <common.h>
+
+#ifdef DEBUG
+
+#define FAILIF(cond, msg...) do {                        \
+       if (unlikely(cond)) {                                \
+        fprintf(stderr, "%s(%d): ", __FILE__, __LINE__); \
+               fprintf(stderr, ##msg);                          \
+               exit(1);                                         \
+       }                                                    \
+} while(0)
+
+/* Debug enabled */
+#define ASSERT(x) do {                                \
+       if (unlikely(!(x))) {                             \
+               fprintf(stderr,                               \
+                               "ASSERTION FAILURE %s:%d: [%s]\n",    \
+                               __FILE__, __LINE__, #x);              \
+               exit(1);                                      \
+       }                                                 \
+} while(0)
+
+#else
+
+#define FAILIF(cond, msg...) do { \
+       if (unlikely(cond)) {         \
+               fprintf(stderr, ##msg);   \
+               exit(1);                  \
+       }                             \
+} while(0)
+
+/* No debug */
+#define ASSERT(x)   do { } while(0)
+
+#endif/* DEBUG */
+
+#define FAILIF_LIBELF(cond, function) \
+    FAILIF(cond, "%s(): %s\n", #function, elf_errmsg(elf_errno()));
+
+static inline void *MALLOC(unsigned int size) 
+{
+    void *m = malloc(size);
+    FAILIF(NULL == m, "malloc(%d) failed!\n", size);
+    return m;
+}
+
+static inline void *CALLOC(unsigned int num_entries, unsigned int entry_size) 
+{
+    void *m = calloc(num_entries, entry_size);
+    FAILIF(NULL == m, "calloc(%d, %d) failed!\n", num_entries, entry_size);
+    return m;
+}
+
+static inline void *REALLOC(void *ptr, unsigned int size) 
+{
+    void *m = realloc(ptr, size);
+    FAILIF(NULL == m, "realloc(%p, %d) failed!\n", ptr, size);
+    return m;
+}
+
+static inline void FREE(void *ptr)
+{
+    free(ptr);
+}
+
+static inline void FREEIF(void *ptr)
+{
+    if (ptr) FREE(ptr);
+}
+
+#define PRINT(x...)  do {                             \
+    extern int quiet_flag;                            \
+    if(likely(!quiet_flag))                           \
+        fprintf(stdout, ##x);                         \
+} while(0)
+
+#define ERROR(x...) fprintf(stderr, ##x)
+
+#define INFO(x...)  do {                              \
+    extern int verbose_flag;                          \
+    if(unlikely(verbose_flag))                        \
+        fprintf(stdout, ##x);                         \
+} while(0)
+
+/* Prints a hex and ASCII dump of the selected buffer to the selected stream. */
+int dump_hex_buffer(FILE *s, void *b, size_t l, size_t elsize);
+
+#endif/*DEBUG_H*/
diff --git a/build/tools/lsd/hash.c b/build/tools/lsd/hash.c
new file mode 100644 (file)
index 0000000..bbac675
--- /dev/null
@@ -0,0 +1,29 @@
+#include <common.h>
+#include <debug.h>
+#include <libelf.h>
+#include <hash.h>
+#include <string.h>
+
+int hash_lookup(Elf *elf, 
+                Elf_Data *hash,
+                Elf_Data *symtab,
+                Elf_Data *symstr,
+                const char *symname)
+{
+    Elf32_Word *hash_data = (Elf32_Word *)hash->d_buf;
+    Elf32_Word index;
+    Elf32_Word nbuckets = *hash_data++;
+    Elf32_Word *buckets = ++hash_data;
+    Elf32_Word *chains  = hash_data + nbuckets;
+
+    index = buckets[elf_hash(symname) % nbuckets];
+    while(index != STN_UNDEF &&
+          strcmp((char *)symstr->d_buf + 
+                 ((Elf32_Sym *)symtab->d_buf)[index].st_name,
+                 symname))
+    {
+        index = chains[index];
+    }
+
+    return index;
+}
diff --git a/build/tools/lsd/hash.h b/build/tools/lsd/hash.h
new file mode 100644 (file)
index 0000000..af29b9e
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef HASH_H
+#define HASH_H
+
+#include <common.h>
+#include <libelf.h>
+#include <gelf.h>
+
+int hash_lookup(Elf *elf, 
+                Elf_Data *hash,
+                Elf_Data *symtab,
+                Elf_Data *symstr,
+                const char *symname);
+
+#endif/*HASH_H*/
diff --git a/build/tools/lsd/lsd.c b/build/tools/lsd/lsd.c
new file mode 100644 (file)
index 0000000..03c235b
--- /dev/null
@@ -0,0 +1,777 @@
+#include <stdio.h>
+#include <common.h>
+#include <debug.h>
+#include <libelf.h>
+#include <libebl.h>
+#include <elf.h>
+#include <gelf.h>
+#include <string.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <hash.h>
+#include <lsd.h>
+
+extern int verbose_flag;
+
+typedef struct source_t source_t;
+
+typedef struct {
+    Elf_Scn *scn;
+    GElf_Shdr shdr;
+    Elf_Data *data;
+} section_info_t;
+
+typedef struct next_export_t { 
+    source_t *source;
+    int next_idx;
+} next_export_t;
+
+struct source_t {
+    source_t *next;
+    int visited;
+
+    char *name;  /* full path name of this executable file */
+    /* ELF-related information: */
+    Elf *elf;
+    int elf_fd;
+    GElf_Ehdr elf_hdr;
+    size_t shstrndx;
+    int shnum; /* number of sections */
+
+    section_info_t symtab;
+    section_info_t strtab;
+    section_info_t dynamic;
+    section_info_t hash;
+
+    section_info_t *relocations;
+    int num_relocations; /* number of relocs (<= relocations_size) */
+    int relocations_size; /* sice of array -- NOT number of relocs! */
+
+       /* satisfied_execs: array containing pointers to the libraries or 
+          executables that this executable satisfies symbol references for. */
+       source_t **satisfied_execs;
+    int num_satisfied_execs;
+    int satisfied_execs_size;
+
+    /* satisfied: array is parallel to symbol table; for each undefined symbol 
+       in that array, we maintain a flag stating whether that symbol has been 
+       satisfied, and if so, by which library.  This applies both to executable
+       files and libraries.
+    */
+    source_t **satisfied;
+
+    /* exports: array is parallel to symbol table; for each global symbol 
+       in that array, we maintain a flag stating whether that symbol satisfies 
+       a dependency in some other file.  num_syms is the length of the exports
+       array, as well as the satisfied array. This applied to libraries only.
+
+       next_exports:  this is a bit tricky.  We use this field to maintain a 
+       linked list of source_t for each global symbol of a shared library. 
+       For a shared library's global symbol at index N has the property that
+       exports[N] is the head of a linked list (threaded through next_export)
+       of all source_t that this symbol resolves a reference to.  For example, 
+       if symbol printf has index 1000 in libc.so, and an executable A and 
+       library L use printf, then the source_t entry corresponding to libc.so
+       will have exports[1000] be a linked list that contains the nodes for 
+       application A and library L.
+    */
+
+    next_export_t *exports;
+    /* num_exported is the number of symbols in this file actually used by
+       somebody else;  it's not the size of the exports array. */
+    int num_exported;
+    next_export_t *next_export;
+    int num_next_export;
+    int next_export_size;
+
+    int num_syms; /* number of symbols in symbol table.  This is the length of
+                     both exports[] and satisfied[] arrays. */
+
+    /* This is an array that contains one element for each library dependency
+       listed in the executable or shared library. */
+    source_t **lib_deps; /* list of library dependencies */
+    int num_lib_deps; /* actual number of library dependencies */
+    int lib_deps_size; /* size of lib_deps array--NOT actual number of deps! */
+
+};
+
+static source_t *sources = NULL;
+
+static char * find_file(const char *libname, 
+                        char **lib_lookup_dirs, 
+                        int num_lib_lookup_dirs);
+
+static inline source_t* find_source(const char *name,
+                                    char **lib_lookup_dirs, 
+                                    int num_lib_lookup_dirs) {
+    source_t *trav = sources;
+       char *full = find_file(name, lib_lookup_dirs, num_lib_lookup_dirs);
+    FAILIF(full == NULL, "Cannot construct full path for file [%s]!\n", name);
+    while (trav) {
+        if (!strcmp(trav->name, full))
+            break;
+        trav = trav->next;
+    }
+       free(full);
+    return trav;
+}
+
+static inline void add_to_sources(source_t *src) {
+    src->next = sources;
+    sources = src;
+}
+
+static source_t* init_source(char *full_path) {
+    source_t *source = (source_t *)CALLOC(1, sizeof(source_t));
+
+    ASSERT(full_path);
+    source->name = full_path;
+    source->elf_fd = -1;
+
+    INFO("Opening %s...\n", full_path);
+    source->elf_fd = open(full_path, O_RDONLY);
+    FAILIF(source->elf_fd < 0, "open(%s): %s (%d)\n", 
+           full_path, 
+           strerror(errno), 
+           errno);
+    INFO("Calling elf_begin(%s)...\n", full_path);
+    source->elf = elf_begin(source->elf_fd, ELF_C_READ, NULL);
+    FAILIF_LIBELF(source->elf == NULL, elf_begin);
+
+    /* libelf can recognize COFF and A.OUT formats, but we handle only ELF. */
+    if (elf_kind(source->elf) != ELF_K_ELF) {
+        ERROR("Input file %s is not in ELF format!\n", full_path);
+        return NULL;
+    }
+
+    /* Make sure this is a shared library or an executable. */
+    {
+        INFO("Making sure %s is a shared library or an executable...\n", 
+             full_path);
+        FAILIF_LIBELF(0 == gelf_getehdr(source->elf, &source->elf_hdr), gelf_getehdr);
+        FAILIF(source->elf_hdr.e_type != ET_DYN && 
+               source->elf_hdr.e_type != ET_EXEC,
+               "%s must be a shared library (elf type is %d, expecting %d).\n", 
+               full_path,
+               source->elf_hdr.e_type, 
+               ET_DYN);
+    }
+
+    /* Get the index of the section-header-strings-table section. */
+    FAILIF_LIBELF(elf_getshstrndx (source->elf, &source->shstrndx) < 0, 
+                  elf_getshstrndx);
+
+    FAILIF_LIBELF(elf_getshnum (source->elf, &source->shnum) < 0, elf_getshnum);
+
+    /* Find various sections. */
+    size_t scnidx;
+    Elf_Scn *scn;
+    GElf_Shdr *shdr, shdr_mem;
+    INFO("Locating %d sections in %s...\n", source->shnum, full_path);
+    for (scnidx = 1; scnidx < source->shnum; scnidx++) {
+        scn = elf_getscn(source->elf, scnidx);
+        FAILIF_LIBELF(NULL == scn, elf_getscn);
+        shdr = gelf_getshdr(scn, &shdr_mem);
+        FAILIF_LIBELF(NULL == shdr, gelf_getshdr);
+        INFO("\tfound section [%s]...\n", elf_strptr(source->elf, source->shstrndx, shdr->sh_name));
+        if (shdr->sh_type == SHT_DYNSYM) {
+            source->symtab.scn = scn;
+            source->symtab.data = elf_getdata(scn, NULL);
+            FAILIF_LIBELF(NULL == source->symtab.data, elf_getdata);
+            memcpy(&source->symtab.shdr, shdr, sizeof(GElf_Shdr));
+
+            /* The sh_link field of the section header of the symbol table
+               contains the index of the associated strings table. */
+            source->strtab.scn = elf_getscn(source->elf, 
+                                            source->symtab.shdr.sh_link);
+            FAILIF_LIBELF(NULL == source->strtab.scn, elf_getscn);
+            FAILIF_LIBELF(NULL == gelf_getshdr(scn, &source->strtab.shdr),
+                          gelf_getshdr);
+            source->strtab.data = elf_getdata(source->strtab.scn, NULL);
+            FAILIF_LIBELF(NULL == source->strtab.data, elf_getdata);
+        }
+        else if (shdr->sh_type == SHT_DYNAMIC) {
+            source->dynamic.scn = scn;
+            source->dynamic.data = elf_getdata(scn, NULL);
+            FAILIF_LIBELF(NULL == source->symtab.data, elf_getdata);
+            memcpy(&source->dynamic.shdr, shdr, sizeof(GElf_Shdr));
+        }
+        else if (shdr->sh_type == SHT_HASH) {
+            source->hash.scn = scn;
+            source->hash.data = elf_getdata(scn, NULL);
+            FAILIF_LIBELF(NULL == source->hash.data, elf_getdata);
+            memcpy(&source->hash.shdr, shdr, sizeof(GElf_Shdr));
+        }
+        else if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) {
+            if (source->num_relocations == source->relocations_size) {
+                source->relocations_size += 5;
+                source->relocations = 
+                    (section_info_t *)REALLOC(source->relocations,
+                                              source->relocations_size *
+                                              sizeof(section_info_t));
+            }
+            section_info_t *reloc = 
+                source->relocations + source->num_relocations;
+            reloc->scn = scn;
+            reloc->data = elf_getdata(scn, NULL);
+            FAILIF_LIBELF(NULL == reloc->data, elf_getdata);
+            memcpy(&reloc->shdr, shdr, sizeof(GElf_Shdr));
+            source->num_relocations++;
+        }
+    }
+
+    if (source->dynamic.scn == NULL) {
+        INFO("File [%s] does not have a dynamic section!\n", full_path);
+        return 0;
+    }
+
+    FAILIF(source->symtab.scn == NULL, 
+           "File [%s] does not have a dynamic symbol table!\n",
+           full_path);
+
+    FAILIF(source->hash.scn == NULL, 
+           "File [%s] does not have a hash table!\n",
+           full_path);
+    FAILIF(source->hash.shdr.sh_link != elf_ndxscn(source->symtab.scn),
+           "Hash points to section %d, not to %d as expected!\n",
+           source->hash.shdr.sh_link,
+           elf_ndxscn(scn));
+
+    /* Now, find out how many symbols we have and allocate the array of 
+       satisfied symbols.
+
+       NOTE: We don't count the number of undefined symbols here; we will 
+       iterate over the symbol table later, and count them then, when it is 
+       more convenient. 
+    */
+    size_t symsize = gelf_fsize (source->elf, 
+                                 ELF_T_SYM, 
+                                 1, source->elf_hdr.e_version);
+    ASSERT(symsize);
+
+    source->num_syms = source->symtab.data->d_size / symsize;
+    source->satisfied = (source_t **)CALLOC(source->num_syms, 
+                                            sizeof(source_t *));
+    source->exports = (source_t **)CALLOC(source->num_syms, 
+                                          sizeof(next_export_t));
+
+    source->num_exported = 0;
+    source->satisfied_execs = NULL;
+    source->num_satisfied_execs = 0;
+    source->satisfied_execs_size = 0;
+
+    add_to_sources(source);
+    return source;
+}
+
+static void destroy_source(source_t *source) {
+    FREE(source->satisfied_execs);
+    FREE(source->satisfied);
+    FREE(source->exports);
+    FREE(source->next_export);    
+    FREE(source->lib_deps); /* list of library dependencies */
+    FAILIF_LIBELF(elf_end(source->elf), elf_end);
+    FAILIF(close(source->elf_fd) < 0, "Could not close file %s: %s (%d)!\n", 
+           source->name, strerror(errno), errno);
+    FREE(source->name);
+    FREE(source);
+}
+
+static void print_needed_libs(source_t *source)
+{
+       size_t idx;
+       for (idx = 0; idx < source->num_lib_deps; idx++) {
+               PRINT("%s:%s\n", 
+                         source->name, 
+                         source->lib_deps[idx]->name);
+       }
+}
+
+static int is_symbol_imported(source_t *source,
+                              GElf_Sym *sym, 
+                              size_t symidx)
+{
+    const char *symname = elf_strptr(source->elf,
+                                     elf_ndxscn(source->strtab.scn),
+                                     sym->st_name);
+
+    /* A symbol is imported by an executable or a library if it is undefined
+       and is either global or weak. There is an additional case for 
+       executables that we will check below. */
+    if (sym->st_shndx == SHN_UNDEF &&
+        (GELF_ST_BIND(sym->st_info) == STB_GLOBAL ||
+         GELF_ST_BIND(sym->st_info) == STB_WEAK)) {
+        INFO("*** symbol [%s:%s] is imported (UNDEFIEND).\n",
+             source->name,
+             symname);
+        return 1;
+    }
+
+#ifdef ARM_SPECIFIC_HACKS
+    /* A symbol is imported by an executable if is marked as an undefined 
+       symbol--this is standard to all ELF formats.  Alternatively, according 
+       to the ARM specifications, a symbol in a BSS section that is also marked
+       by an R_ARM_COPY relocation is also imported. */
+
+    if (source->elf_hdr.e_type != ET_EXEC) {
+        INFO("is_symbol_imported(): [%s] is a library, "
+             "no further checks.\n", source->name);
+        return 0;
+    }
+
+    /* Is the symbol in the BSS section, and is there a COPY relocation on 
+       that symbol? */
+    INFO("*** [%s:%s] checking further to see if symbol is imported.\n",
+         source->name, symname);
+    if (sym->st_shndx < source->shnum) {
+        /* Is it the .bss section? */
+        Elf_Scn *scn = elf_getscn(source->elf, sym->st_shndx);
+        FAILIF_LIBELF(NULL == scn, elf_getscn);
+        GElf_Shdr *shdr, shdr_mem;
+        shdr = gelf_getshdr(scn, &shdr_mem);
+        FAILIF_LIBELF(NULL == shdr, gelf_getshdr);
+        if (!strcmp(".bss", elf_strptr(source->elf,
+                                       source->shstrndx,
+                                       shdr->sh_name)))
+        {
+            /* Is there an R_ARM_COPY relocation on this symbol?  Iterate 
+               over the list of relocation sections and scan each section for
+               an entry that matches the symbol. */
+            size_t idx;
+            for (idx = 0; idx < source->num_relocations; idx++) {
+                section_info_t *reloc = source->relocations + idx;
+                /* Does the relocation section refer to the symbol table in
+                   which this symbol resides, and does it relocate the .bss
+                   section? */
+                if (reloc->shdr.sh_link == elf_ndxscn(source->symtab.scn) &&
+                    reloc->shdr.sh_info == sym->st_shndx)
+                {
+                    /* Go over the relocations and see if any of them matches
+                       our symbol. */
+                    size_t nrels = reloc->shdr.sh_size / reloc->shdr.sh_entsize;
+                    size_t relidx, newidx;
+                    if (reloc->shdr.sh_type == SHT_REL) {
+                        for (newidx = relidx = 0; relidx < nrels; ++relidx) {
+                            GElf_Rel rel_mem;
+                            FAILIF_LIBELF(gelf_getrel (reloc->data, 
+                                                       relidx, 
+                                                       &rel_mem) == NULL,
+                                          gelf_getrel);
+                            if (GELF_R_TYPE(rel_mem.r_info) == R_ARM_COPY &&
+                                GELF_R_SYM (rel_mem.r_info) == symidx)
+                            {
+                                INFO("*** symbol [%s:%s] is imported "
+                                     "(DEFINED, REL-COPY-RELOCATED).\n",
+                                     source->name,
+                                     symname);
+                                return 1;
+                            }
+                        } /* for each rel entry... */
+                    } else {
+                        for (newidx = relidx = 0; relidx < nrels; ++relidx) {
+                            GElf_Rela rel_mem;
+                            FAILIF_LIBELF(gelf_getrela (reloc->data, 
+                                                        relidx, 
+                                                        &rel_mem) == NULL,
+                                          gelf_getrela);
+                            if (GELF_R_TYPE(rel_mem.r_info) == R_ARM_COPY &&
+                                GELF_R_SYM (rel_mem.r_info) == symidx)
+                            {
+                                INFO("*** symbol [%s:%s] is imported "
+                                     "(DEFINED, RELA-COPY-RELOCATED).\n",
+                                     source->name,
+                                     symname);
+                                return 1;
+                            }
+                        } /* for each rela entry... */
+                    } /* if rel else rela */
+                }
+            }
+        }
+    }
+#endif/*ARM_SPECIFIC_HACKS*/
+
+    return 0;
+}
+
+static void resolve(source_t *source) {
+    /* Iterate the symbol table.  For each undefined symbol, scan the 
+       list of dependencies till we find a global symbol in one of them that 
+       satisfies the undefined reference.  At this point, we update both the 
+       satisfied[] array of the sources entry, as well as the exports array of 
+       the dependency where we found the match.
+    */
+
+    GElf_Sym *sym, sym_mem;
+    size_t symidx;
+    for (symidx = 0; symidx < source->num_syms; symidx++) {
+        sym = gelf_getsymshndx(source->symtab.data, 
+                               NULL,
+                               symidx,
+                               &sym_mem,
+                               NULL);
+        FAILIF_LIBELF(NULL == sym, gelf_getsymshndx);
+        if (is_symbol_imported(source, sym, symidx)) 
+               {
+            /* This is an undefined symbol.  Go over the list of libraries 
+               and look it up. */
+            size_t libidx;
+                       int found = 0;
+                       source_t *last_found = NULL;
+                       const char *symname = elf_strptr(source->elf,
+                                                                                        elf_ndxscn(source->strtab.scn),
+                                                                                        sym->st_name);
+            for (libidx = 0; libidx < source->num_lib_deps; libidx++) {
+                source_t *lib = source->lib_deps[libidx];
+                int lib_symidx = hash_lookup(lib->elf,
+                                             lib->hash.data,
+                                             lib->symtab.data,
+                                             lib->strtab.data,
+                                             symname);
+                if (STN_UNDEF != lib_symidx)
+                {
+                                       /* We found the symbol--now check to see if it is global 
+                                          or weak.  If this is the case, then the symbol satisfies
+                                          the dependency. */
+                                       GElf_Sym *lib_sym, lib_sym_mem;
+                                       lib_sym = gelf_getsymshndx(lib->symtab.data, 
+                                                                                          NULL,
+                                                                                          lib_symidx,
+                                                                                          &lib_sym_mem,
+                                                                                          NULL);
+                                       FAILIF_LIBELF(NULL == lib_sym, gelf_getsymshndx);
+
+                                       if(lib_sym->st_shndx != STN_UNDEF &&
+                                          (GELF_ST_BIND(lib_sym->st_info) == STB_GLOBAL ||
+                                               GELF_ST_BIND(lib_sym->st_info) == STB_WEAK))
+                                       {
+                                               /* We found the symbol! Update the satisfied array at this
+                                                  index location. */
+                                               source->satisfied[symidx] = lib;
+                                               /* Now, link this structure into the linked list 
+                                                  corresponding to the found symbol in the library's 
+                                                  global array. */
+                        if (source->num_next_export == source->next_export_size) {
+                            source->next_export_size += 30;
+                            source->next_export = 
+                                (source_t **)REALLOC(source->next_export,
+                                                     source->next_export_size *
+                                                     sizeof(struct next_export_t));
+                        }
+                        source->next_export[source->num_next_export] = lib->exports[lib_symidx];
+                        lib->exports[lib_symidx].source = source;
+                        lib->exports[lib_symidx].next_idx = source->num_next_export;
+
+                        source->num_next_export++;
+                        lib->num_exported++;
+
+                        INFO("[%s:%s (index %d)] satisfied by [%s] (index %d)\n",
+                                                        source->name,
+                                                        symname,
+                                                        symidx,
+                                                        lib->name,
+                                                        lib_symidx);
+                                               if (found) {
+                                                       if (found == 1) {
+                                                               found++;
+                                                               ERROR("ERROR: multiple definitions found for [%s:%s]!\n",
+                                                                         source->name, symname);
+                                                               ERROR("\tthis definition     [%s]\n", lib->name);
+                                                       }
+                                                       ERROR("\tprevious definition [%s]\n", last_found->name);
+                                               }
+
+                                               last_found = lib;
+                                               if (!found) found = 1;
+                                       }
+                }
+            }
+                       if(found == 0) {
+                               ERROR("ERROR: could not find match for %s:%s.\n", 
+                                         source->name, 
+                                         symname);
+                       }
+        } /* if we found the symbol... */
+    } /* for each symbol... */
+} /* resolve() */
+
+static void print_used_symbols(source_t *source) {
+
+    int name_len = strlen(source->name);
+    static const char ext[] = ".syms";
+    char *filter = (char *)MALLOC(name_len + sizeof(ext));
+    strcpy(filter, source->name);
+    strcpy(filter + name_len, ext);
+
+    FILE *fp = fopen(filter, "w+");
+    FAILIF(NULL == fp, 
+           "Can't open %s: %s (%d)\n", 
+           filter, 
+           strerror(errno), errno);
+    
+    /* Is anybody using the symbols defined in source? */
+
+    if (source->num_exported > 0) {
+        INFO("[%s] exports %d symbols to %d libraries and executables.\n",
+             source->name,
+             source->num_exported,
+             source->num_satisfied_execs);
+        size_t symidx;
+        for (symidx = 0; symidx < source->num_syms; symidx++) {
+            if (source->exports[symidx].source != NULL) {
+                GElf_Sym *sym, sym_mem;
+                sym = gelf_getsymshndx(source->symtab.data, 
+                                       NULL,
+                                       symidx,
+                                       &sym_mem,
+                                       NULL);
+                FAILIF_LIBELF(NULL == sym, gelf_getsymshndx);
+                fprintf(fp, "%s\n", elf_strptr(source->elf,
+                                               elf_ndxscn(source->strtab.scn),
+                                               sym->st_name));
+            }
+        }
+    }
+    else if (source->num_satisfied_execs > 0) {
+
+        /*  Is the source listed as a depenency on anyone?  If so, then the source exports no symbols
+            to anyone, but someone lists it as a dependency, which is unnecessary, so we print a warning.
+         */
+
+        ERROR("WARNING: [%s] is listed as a dependency in: ", source->name);
+        int i;
+        for (i = 0; i < source->num_satisfied_execs; i++) {
+            ERROR(" [%s],", source->satisfied_execs[i]->name);
+        }
+        ERROR(" but none of its symbols are used!.\n");
+    }
+#if 0 /* This is not really an error--a library's symbols may not be used anyone as specified in the ELF file,
+         but someone may still open a library via dlopen(). 
+      */
+    else {
+        ERROR("WARNING: None of [%s]'s symbols are used by any library or executable!\n", source->name);
+    }
+#endif
+
+       fclose(fp);
+    FREE(filter);
+}
+
+static void print_symbol_references(source_t *source) {
+
+    int name_len = strlen(source->name);
+    static const char ext[] = ".info";
+    char *filter = (char *)MALLOC(name_len + sizeof(ext));
+    strcpy(filter, source->name);
+    strcpy(filter + name_len, ext);
+
+    FILE *fp = fopen(filter, "w+");
+    FAILIF(NULL == fp, 
+           "Can't open %s: %s (%d)\n", 
+           filter, 
+           strerror(errno), errno);
+
+    if (source->num_exported > 0) {
+        size_t symidx;
+        for (symidx = 0; symidx < source->num_syms; symidx++) {
+            if (source->exports[symidx].source != NULL) {
+                const char *symname;
+                GElf_Sym *sym, sym_mem;
+                sym = gelf_getsymshndx(source->symtab.data, 
+                                       NULL,
+                                       symidx,
+                                       &sym_mem,
+                                       NULL);
+                FAILIF_LIBELF(NULL == sym, gelf_getsymshndx);
+                symname = elf_strptr(source->elf, 
+                                     elf_ndxscn(source->strtab.scn),
+                                     sym->st_name);
+                fprintf(fp, "%s\n", symname);
+                next_export_t *export = &source->exports[symidx];
+                while (export->source != NULL) {
+                    //fprintf(stderr, "%s:%s\n", symname, export->source->name);
+                    fprintf(fp, "\t%s\n", export->source->name);
+                    export = &export->source->next_export[export->next_idx];
+                }
+            }
+        }
+    }
+
+       fclose(fp);
+    FREE(filter);
+}
+
+static char * find_file(const char *libname, 
+                        char **lib_lookup_dirs, 
+                        int num_lib_lookup_dirs) {
+    if (libname[0] == '/') {
+        /* This is an absolute path name--just return it. */
+        INFO("ABSOLUTE PATH: [%s].\n", libname);
+        return strdup(libname);
+    } else {
+        /* First try the working directory. */
+        int fd;
+        if ((fd = open(libname, O_RDONLY)) > 0) {
+            close(fd);
+            INFO("FOUND IN CURRENT DIR: [%s].\n", libname);
+            return strdup(libname);
+        } else {
+            /* Iterate over all library paths.  For each path, append the file
+               name and see if there is a file at that place. If that fails, 
+               bail out. */
+
+            char *name;
+            while (num_lib_lookup_dirs--) {
+                size_t lib_len = strlen(*lib_lookup_dirs);
+                /* one extra character for the slash, and another for the 
+                   terminating NULL. */
+                name = (char *)MALLOC(lib_len + strlen(libname) + 2);
+                strcpy(name, *lib_lookup_dirs);
+                name[lib_len] = '/';
+                strcpy(name + lib_len + 1, libname);
+                if ((fd = open(name, O_RDONLY)) > 0) {
+                    close(fd);
+                    INFO("FOUND: [%s] in [%s].\n", libname, name);
+                    return name;
+                }
+                INFO("NOT FOUND: [%s] in [%s].\n", libname, name);
+                free(name);
+            }
+        }
+    }
+    return NULL;
+}
+
+static source_t* process_library(const char *libname,
+                                 char **lib_lookup_dirs, 
+                                 int num_lib_lookup_dirs) {
+    source_t *source = find_source(libname, lib_lookup_dirs, num_lib_lookup_dirs);
+    if (NULL == source) {
+        INFO("Processing [%s].\n", libname);
+        char *full = find_file(libname, lib_lookup_dirs, num_lib_lookup_dirs);
+        FAILIF(NULL == full, 
+               "Could not find [%s] in the current directory or in any of "
+               "the search paths!\n", libname);
+        source = init_source(full);
+        if (source) {
+            GElf_Dyn *dyn, dyn_mem;
+            size_t dynidx;
+            size_t numdyn =
+            source->dynamic.shdr.sh_size / 
+            source->dynamic.shdr.sh_entsize;
+
+            for (dynidx = 0; dynidx < numdyn; dynidx++) {
+                dyn = gelf_getdyn (source->dynamic.data, 
+                                   dynidx, 
+                                   &dyn_mem);
+                FAILIF_LIBELF(NULL == dyn, gelf_getdyn);
+                if (dyn->d_tag == DT_NEEDED) {
+                    /* Process the needed library recursively. */
+                    const char *dep_lib =
+                    elf_strptr (source->elf, 
+                                source->dynamic.shdr.sh_link, 
+                                dyn->d_un.d_val);
+                    INFO("[%s] depends on [%s].\n", libname, dep_lib);
+                    source_t *dep = process_library(dep_lib, 
+                                                    lib_lookup_dirs,
+                                                    num_lib_lookup_dirs);
+
+                    /* Tell dep that source depends on it. */
+                    if (dep->num_satisfied_execs == dep->satisfied_execs_size) {
+                        dep->satisfied_execs_size += 10;
+                        dep->satisfied_execs = 
+                            REALLOC(dep->satisfied_execs,
+                                    dep->satisfied_execs_size *
+                                    sizeof(source_t *));
+                    }
+                    dep->satisfied_execs[dep->num_satisfied_execs++] = source;
+
+                    /* Add the library to the dependency list. */
+                    if (source->num_lib_deps == source->lib_deps_size) {
+                        source->lib_deps_size += 10;
+                        source->lib_deps = REALLOC(source->lib_deps, 
+                                                   source->lib_deps_size *
+                                                   sizeof(source_t *));
+                    }
+                    source->lib_deps[source->num_lib_deps++] = dep;
+                }
+            } /* for each dynamic entry... */
+        }
+    } else INFO("[%s] has been processed already.\n", libname);
+
+    return source;
+}
+
+void lsd(char **execs, int num_execs,
+                int list_needed_libs,
+                int print_info,
+         char **lib_lookup_dirs, int num_lib_lookup_dirs) {
+
+    source_t *source; /* for general usage */
+    int input_idx;
+
+    for (input_idx = 0; input_idx < num_execs; input_idx++) {
+        INFO("executable: [%s]\n", execs[input_idx]);
+        /* Here process library is actually processing the top-level executable
+           files. */
+        process_library(execs[input_idx], lib_lookup_dirs, num_lib_lookup_dirs);
+        /* if source is NULL, then the respective executable is static */
+        /* Mark the source as an executable */
+    } /* for each input executable... */
+
+       if (list_needed_libs) {
+               source = sources;
+               while (source) {
+                       print_needed_libs(source);
+                       source = source->next;
+               }
+       }
+
+    /* Now, for each entry in the sources array, iterate its symbol table.  For
+       each undefined symbol, scan the list of dependencies till we find a 
+       global symbol in one of them that satisfies the undefined reference.  
+       At this point, we update both the satisfied[] array of the sources entry, 
+       as well as the exports array of the dependency where we found the match.
+    */
+
+    source = sources;
+    while (source) {
+        resolve(source);
+        source = source->next;
+    }
+
+    /* We are done!  Since the end result of our calculations is a set of 
+       symbols for each library that other libraries or executables link 
+       against, we iterate over the set of libraries one last time, and for
+       each symbol that is marked as satisfying some dependence, we emit 
+       a line with the symbol's name to a text file derived from the library's
+       name by appending the suffix .syms to it. */
+
+    source = sources;
+    while (source) {
+        /* If it's a library, print the results. */
+        if (source->elf_hdr.e_type == ET_DYN) {
+                       print_used_symbols(source);
+                       if (print_info) 
+                               print_symbol_references(source);
+               }
+        source = source->next;
+    }
+
+       /* Free the resources--you can't do it in the loop above because function 
+          print_symbol_references() accesses nodes other than the one being 
+          iterated over.
+        */
+       source = sources;
+       while (source) {
+               source_t *old = source;
+               source = source->next;
+               /* Destroy the evidence. */
+               destroy_source(old);
+       }
+}
+
diff --git a/build/tools/lsd/lsd.h b/build/tools/lsd/lsd.h
new file mode 100644 (file)
index 0000000..883c423
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef LSD_H
+#define LSD_H
+
+void lsd(char **execs, int num_execs,
+                int list_needed_libs,
+                int print_info,
+         char **lib_lookup_dirs, 
+         int num_lib_lookup_dirs);
+
+#endif
diff --git a/build/tools/lsd/main.c b/build/tools/lsd/main.c
new file mode 100644 (file)
index 0000000..f29157a
--- /dev/null
@@ -0,0 +1,67 @@
+/* TODO:
+   1. check the ARM EABI version--this works for versions 1 and 2.
+   2. use a more-intelligent approach to finding the symbol table, symbol-string
+      table, and the .dynamic section.
+   3. fix the determination of the host and ELF-file endianness
+   4. write the help screen
+*/
+
+#include <stdio.h>
+#include <common.h>
+#include <debug.h>
+#include <libelf.h>
+#include <elf.h>
+#include <gelf.h>
+#include <cmdline.h>
+#include <string.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <lsd.h>
+
+/* Flag set by --verbose.  This variable is global as it is accessed by the
+   macro INFO() in multiple compilation unites. */
+int verbose_flag = 0;
+/* Flag set by --quiet.  This variable is global as it is accessed by the
+   macro PRINT() in multiple compilation unites. */
+int quiet_flag = 0;
+
+int main(int argc, char **argv)
+{
+    char **lookup_dirs = NULL;
+    int num_lookup_dirs;
+       int print_info;
+       int list_needed_libs;
+
+    /* Do not issue INFO() statements before you call get_options() to set 
+       the verbose flag as necessary.
+    */
+
+    int first = get_options(argc, argv,
+                                                       &list_needed_libs,
+                                                       &print_info,
+                            &lookup_dirs,
+                            &num_lookup_dirs,
+                            &verbose_flag);
+
+    if (first == argc) {
+        print_help();
+        FAILIF(1,  "You must specify at least one input ELF file!\n");
+    }
+
+    /* Check to see whether the ELF library is current. */
+    FAILIF (elf_version(EV_CURRENT) == EV_NONE, "libelf is out of date!\n");
+
+    /* List symbol dependencies... */
+    lsd(&argv[first], argc - first, 
+               list_needed_libs, print_info, 
+               lookup_dirs, num_lookup_dirs);
+
+    FREE(lookup_dirs);
+
+    return 0;
+} 
+
diff --git a/build/tools/merge-event-log-tags.py b/build/tools/merge-event-log-tags.py
new file mode 100644 (file)
index 0000000..bddda90
--- /dev/null
@@ -0,0 +1,181 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Usage: merge-event-log-tags.py [-o output_file] [input_files...]
+
+Merge together zero or more event-logs-tags files to produce a single
+output file, stripped of comments.  Checks that no tag numbers conflict
+and fails if they do.
+
+-h to display this usage message and exit.
+"""
+
+import cStringIO
+import getopt
+import md5
+import struct
+import sys
+
+import event_log_tags
+
+errors = []
+warnings = []
+
+output_file = None
+pre_merged_file = None
+
+# Tags with a tag number of ? are assigned a tag in the range
+# [ASSIGN_START, ASSIGN_LIMIT).
+ASSIGN_START = 900000
+ASSIGN_LIMIT = 1000000
+
+try:
+  opts, args = getopt.getopt(sys.argv[1:], "ho:m:")
+except getopt.GetoptError, err:
+  print str(err)
+  print __doc__
+  sys.exit(2)
+
+for o, a in opts:
+  if o == "-h":
+    print __doc__
+    sys.exit(2)
+  elif o == "-o":
+    output_file = a
+  elif o == "-m":
+    pre_merged_file = a
+  else:
+    print >> sys.stderr, "unhandled option %s" % (o,)
+    sys.exit(1)
+
+# Restrictions on tags:
+#
+#   Tag names must be unique.  (If the tag number and description are
+#   also the same, a warning is issued instead of an error.)
+#
+#   Explicit tag numbers must be unique.  (If the tag name is also the
+#   same, no error is issued because the above rule will issue a
+#   warning or error.)
+
+by_tagname = {}
+by_tagnum = {}
+
+pre_merged_tags = {}
+if pre_merged_file:
+  for t in event_log_tags.TagFile(pre_merged_file).tags:
+    pre_merged_tags[t.tagname] = t
+
+for fn in args:
+  tagfile = event_log_tags.TagFile(fn)
+
+  for t in tagfile.tags:
+    tagnum = t.tagnum
+    tagname = t.tagname
+    description = t.description
+
+    if t.tagname in by_tagname:
+      orig = by_tagname[t.tagname]
+
+      # Allow an explicit tag number to define an implicit tag number
+      if orig.tagnum is None:
+        orig.tagnum = t.tagnum
+      elif t.tagnum is None:
+        t.tagnum = orig.tagnum
+
+      if (t.tagnum == orig.tagnum and
+          t.description == orig.description):
+        # if the name and description are identical, issue a warning
+        # instead of failing (to make it easier to move tags between
+        # projects without breaking the build).
+        tagfile.AddWarning("tag \"%s\" (%s) duplicated in %s:%d" %
+                           (t.tagname, t.tagnum, orig.filename, orig.linenum),
+                           linenum=t.linenum)
+      else:
+        tagfile.AddError(
+            "tag name \"%s\" used by conflicting tag %s from %s:%d" %
+            (t.tagname, orig.tagnum, orig.filename, orig.linenum),
+            linenum=t.linenum)
+      continue
+
+    if t.tagnum is not None and t.tagnum in by_tagnum:
+      orig = by_tagnum[t.tagnum]
+
+      if t.tagname != orig.tagname:
+        tagfile.AddError(
+            "tag number %d used by conflicting tag \"%s\" from %s:%d" %
+            (t.tagnum, orig.tagname, orig.filename, orig.linenum),
+            linenum=t.linenum)
+        continue
+
+    by_tagname[t.tagname] = t
+    if t.tagnum is not None:
+      by_tagnum[t.tagnum] = t
+
+  errors.extend(tagfile.errors)
+  warnings.extend(tagfile.warnings)
+
+if errors:
+  for fn, ln, msg in errors:
+    print >> sys.stderr, "%s:%d: error: %s" % (fn, ln, msg)
+  sys.exit(1)
+
+if warnings:
+  for fn, ln, msg in warnings:
+    print >> sys.stderr, "%s:%d: warning: %s" % (fn, ln, msg)
+
+# Python's hash function (a) isn't great and (b) varies between
+# versions of python.  Using md5 is overkill here but is the same from
+# platform to platform and speed shouldn't matter in practice.
+def hashname(str):
+  d = md5.md5(str).digest()[:4]
+  return struct.unpack("!I", d)[0]
+
+# Assign a tag number to all the entries that say they want one
+# assigned.  We do this based on a hash of the tag name so that the
+# numbers should stay relatively stable as tags are added.
+
+# If we were provided pre-merged tags (w/ the -m option), then don't
+# ever try to allocate one, just fail if we don't have a number
+
+for name, t in sorted(by_tagname.iteritems()):
+  if t.tagnum is None:
+    if pre_merged_tags:
+      try:
+        t.tagnum = pre_merged_tags[t.tagname]
+      except KeyError:
+        print >> sys.stderr, ("Error: Tag number not defined for tag `%s'."
+            +" Have you done a full build?") % t.tagname
+        sys.exit(1)
+    else:
+      while True:
+        x = (hashname(name) % (ASSIGN_LIMIT - ASSIGN_START - 1)) + ASSIGN_START
+        if x not in by_tagnum:
+          t.tagnum = x
+          by_tagnum[x] = t
+          break
+        name = "_" + name
+
+# by_tagnum should be complete now; we've assigned numbers to all tags.
+
+buffer = cStringIO.StringIO()
+for n, t in sorted(by_tagnum.iteritems()):
+  if t.description:
+    buffer.write("%d %s %s\n" % (t.tagnum, t.tagname, t.description))
+  else:
+    buffer.write("%d %s\n" % (t.tagnum, t.tagname))
+
+event_log_tags.WriteOutput(output_file, buffer)
diff --git a/build/tools/mktarball.sh b/build/tools/mktarball.sh
new file mode 100644 (file)
index 0000000..3e32006
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/bash
+
+# $1: path to fs_get_stats program
+# $2: start dir
+# $3: subdir to tar up (from $2)
+# $4: target tar name
+# $5: target tarball name (usually $(3).bz2)
+
+if [ $# -ne 5 ]; then
+    echo "Error: wrong number of arguments in cmd: $0 $* "
+    exit 1
+fi
+
+fs_get_stats=`readlink -f $1`
+start_dir=`readlink -f $2`
+dir_to_tar=$3
+target_tar=`readlink -f $4`
+target_tarball=`readlink -f $5`
+
+cd $2
+
+#tar --no-recursion -cvf ${target_tar} ${dir_to_tar}
+rm ${target_tar} > /dev/null 2>&1
+
+# do dirs first
+subdirs=`find ${dir_to_tar} -type d -print`
+files=`find ${dir_to_tar} \! -type d -print`
+for f in ${subdirs} ${files} ; do
+    curr_perms=`stat -c 0%a $f`
+    [ -d "$f" ] && is_dir=1 || is_dir=0
+    new_info=`${fs_get_stats} ${curr_perms} ${is_dir} ${f}`
+    new_uid=`echo ${new_info} | awk '{print $1;}'`
+    new_gid=`echo ${new_info} | awk '{print $2;}'`
+    new_perms=`echo ${new_info} | awk '{print $3;}'`
+#    echo "$f: dir: $is_dir curr: $curr_perms uid: $new_uid gid: $new_gid "\
+#         "perms: $new_perms"
+    tar --no-recursion --numeric-owner --owner $new_uid \
+        --group $new_gid --mode $new_perms -p -rf ${target_tar} ${f}
+done
+
+if [ $? -eq 0 ] ; then
+    case "${target_tarball}" in
+    *.bz2 )
+        bzip2 -c ${target_tar} > ${target_tarball}
+        ;;
+    *.gz )
+        gzip -c ${target_tar} > ${target_tarball}
+        ;;
+    esac
+    success=$?
+    [ $success -eq 0 ] || rm -f ${target_tarball}
+    rm -f ${target_tar}
+    exit $success
+fi
+
+rm -f ${target_tar}
+exit 1
diff --git a/build/tools/print_module_licenses.sh b/build/tools/print_module_licenses.sh
new file mode 100644 (file)
index 0000000..b84f7d4
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/sh
+find . -name MODULE_LICENSE_\* | sed 's/\/MODULE_LICENSE_/\ /' | sed 's/\.\///' | awk '{ print $2 " " $1; }' | sort
diff --git a/build/tools/releasetools/check_target_files_signatures b/build/tools/releasetools/check_target_files_signatures
new file mode 100644 (file)
index 0000000..17aebdc
--- /dev/null
@@ -0,0 +1,449 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Check the signatures of all APKs in a target_files .zip file.  With
+-c, compare the signatures of each package to the ones in a separate
+target_files (usually a previously distributed build for the same
+device) and flag any changes.
+
+Usage:  check_target_file_signatures [flags] target_files
+
+  -c  (--compare_with)  <other_target_files>
+      Look for compatibility problems between the two sets of target
+      files (eg., packages whose keys have changed).
+
+  -l  (--local_cert_dirs)  <dir,dir,...>
+      Comma-separated list of top-level directories to scan for
+      .x509.pem files.  Defaults to "vendor,build".  Where cert files
+      can be found that match APK signatures, the filename will be
+      printed as the cert name, otherwise a hash of the cert plus its
+      subject string will be printed instead.
+
+  -t  (--text)
+      Dump the certificate information for both packages in comparison
+      mode (this output is normally suppressed).
+
+"""
+
+import sys
+
+if sys.hexversion < 0x02040000:
+  print >> sys.stderr, "Python 2.4 or newer is required."
+  sys.exit(1)
+
+import os
+import re
+import sha
+import shutil
+import subprocess
+import tempfile
+import zipfile
+
+import common
+
+# Work around a bug in python's zipfile module that prevents opening
+# of zipfiles if any entry has an extra field of between 1 and 3 bytes
+# (which is common with zipaligned APKs).  This overrides the
+# ZipInfo._decodeExtra() method (which contains the bug) with an empty
+# version (since we don't need to decode the extra field anyway).
+class MyZipInfo(zipfile.ZipInfo):
+  def _decodeExtra(self):
+    pass
+zipfile.ZipInfo = MyZipInfo
+
+OPTIONS = common.OPTIONS
+
+OPTIONS.text = False
+OPTIONS.compare_with = None
+OPTIONS.local_cert_dirs = ("vendor", "build")
+
+PROBLEMS = []
+PROBLEM_PREFIX = []
+
+def AddProblem(msg):
+  PROBLEMS.append(" ".join(PROBLEM_PREFIX) + " " + msg)
+def Push(msg):
+  PROBLEM_PREFIX.append(msg)
+def Pop():
+  PROBLEM_PREFIX.pop()
+
+
+def Banner(msg):
+  print "-" * 70
+  print "  ", msg
+  print "-" * 70
+
+
+def GetCertSubject(cert):
+  p = common.Run(["openssl", "x509", "-inform", "DER", "-text"],
+                 stdin=subprocess.PIPE,
+                 stdout=subprocess.PIPE)
+  out, err = p.communicate(cert)
+  if err and not err.strip():
+    return "(error reading cert subject)"
+  for line in out.split("\n"):
+    line = line.strip()
+    if line.startswith("Subject:"):
+      return line[8:].strip()
+  return "(unknown cert subject)"
+
+
+class CertDB(object):
+  def __init__(self):
+    self.certs = {}
+
+  def Add(self, cert, name=None):
+    if cert in self.certs:
+      if name:
+        self.certs[cert] = self.certs[cert] + "," + name
+    else:
+      if name is None:
+        name = "unknown cert %s (%s)" % (sha.sha(cert).hexdigest()[:12],
+                                         GetCertSubject(cert))
+      self.certs[cert] = name
+
+  def Get(self, cert):
+    """Return the name for a given cert."""
+    return self.certs.get(cert, None)
+
+  def FindLocalCerts(self):
+    to_load = []
+    for top in OPTIONS.local_cert_dirs:
+      for dirpath, dirnames, filenames in os.walk(top):
+        certs = [os.path.join(dirpath, i)
+                 for i in filenames if i.endswith(".x509.pem")]
+        if certs:
+          to_load.extend(certs)
+
+    for i in to_load:
+      f = open(i)
+      cert = ParseCertificate(f.read())
+      f.close()
+      name, _ = os.path.splitext(i)
+      name, _ = os.path.splitext(name)
+      self.Add(cert, name)
+
+ALL_CERTS = CertDB()
+
+
+def ParseCertificate(data):
+  """Parse a PEM-format certificate."""
+  cert = []
+  save = False
+  for line in data.split("\n"):
+    if "--END CERTIFICATE--" in line:
+      break
+    if save:
+      cert.append(line)
+    if "--BEGIN CERTIFICATE--" in line:
+      save = True
+  cert = "".join(cert).decode('base64')
+  return cert
+
+
+def CertFromPKCS7(data, filename):
+  """Read the cert out of a PKCS#7-format file (which is what is
+  stored in a signed .apk)."""
+  Push(filename + ":")
+  try:
+    p = common.Run(["openssl", "pkcs7",
+                    "-inform", "DER",
+                    "-outform", "PEM",
+                    "-print_certs"],
+                   stdin=subprocess.PIPE,
+                   stdout=subprocess.PIPE)
+    out, err = p.communicate(data)
+    if err and not err.strip():
+      AddProblem("error reading cert:\n" + err)
+      return None
+
+    cert = ParseCertificate(out)
+    if not cert:
+      AddProblem("error parsing cert output")
+      return None
+    return cert
+  finally:
+    Pop()
+
+
+class APK(object):
+  def __init__(self, full_filename, filename):
+    self.filename = filename
+    self.cert = None
+    Push(filename+":")
+    try:
+      self.RecordCert(full_filename)
+      self.ReadManifest(full_filename)
+    finally:
+      Pop()
+
+  def RecordCert(self, full_filename):
+    try:
+      f = open(full_filename)
+      apk = zipfile.ZipFile(f, "r")
+      pkcs7 = None
+      for info in apk.infolist():
+        if info.filename.startswith("META-INF/") and \
+           (info.filename.endswith(".DSA") or info.filename.endswith(".RSA")):
+          if pkcs7 is not None:
+            AddProblem("multiple certs")
+          pkcs7 = apk.read(info.filename)
+          self.cert = CertFromPKCS7(pkcs7, info.filename)
+          ALL_CERTS.Add(self.cert)
+      if not pkcs7:
+        AddProblem("no signature")
+    finally:
+      f.close()
+
+  def ReadManifest(self, full_filename):
+    p = common.Run(["aapt", "dump", "xmltree", full_filename,
+                    "AndroidManifest.xml"],
+                   stdout=subprocess.PIPE)
+    manifest, err = p.communicate()
+    if err:
+      AddProblem("failed to read manifest")
+      return
+
+    self.shared_uid = None
+    self.package = None
+
+    for line in manifest.split("\n"):
+      line = line.strip()
+      m = re.search('A: (\S*?)(?:\(0x[0-9a-f]+\))?="(.*?)" \(Raw', line)
+      if m:
+        name = m.group(1)
+        if name == "android:sharedUserId":
+          if self.shared_uid is not None:
+            AddProblem("multiple sharedUserId declarations")
+          self.shared_uid = m.group(2)
+        elif name == "package":
+          if self.package is not None:
+            AddProblem("multiple package declarations")
+          self.package = m.group(2)
+
+    if self.package is None:
+      AddProblem("no package declaration")
+
+
+class TargetFiles(object):
+  def __init__(self):
+    self.max_pkg_len = 30
+    self.max_fn_len = 20
+
+  def LoadZipFile(self, filename):
+    d = common.UnzipTemp(filename, '*.apk')
+    try:
+      self.apks = {}
+      self.apks_by_basename = {}
+      for dirpath, dirnames, filenames in os.walk(d):
+        for fn in filenames:
+          if fn.endswith(".apk"):
+            fullname = os.path.join(dirpath, fn)
+            displayname = fullname[len(d)+1:]
+            apk = APK(fullname, displayname)
+            self.apks[apk.package] = apk
+            self.apks_by_basename[os.path.basename(apk.filename)] = apk
+
+            self.max_pkg_len = max(self.max_pkg_len, len(apk.package))
+            self.max_fn_len = max(self.max_fn_len, len(apk.filename))
+    finally:
+      shutil.rmtree(d)
+
+    z = zipfile.ZipFile(open(filename, "rb"))
+    self.certmap = common.ReadApkCerts(z)
+    z.close()
+
+  def CheckSharedUids(self):
+    """Look for any instances where packages signed with different
+    certs request the same sharedUserId."""
+    apks_by_uid = {}
+    for apk in self.apks.itervalues():
+      if apk.shared_uid:
+        apks_by_uid.setdefault(apk.shared_uid, []).append(apk)
+
+    for uid in sorted(apks_by_uid.keys()):
+      apks = apks_by_uid[uid]
+      for apk in apks[1:]:
+        if apk.cert != apks[0].cert:
+          break
+      else:
+        # all the certs are the same; this uid is fine
+        continue
+
+      AddProblem("uid %s shared across multiple certs" % (uid,))
+
+      print "uid %s is shared by packages with different certs:" % (uid,)
+      x = [(i.cert, i.package, i) for i in apks]
+      x.sort()
+      lastcert = None
+      for cert, _, apk in x:
+        if cert != lastcert:
+          lastcert = cert
+          print "    %s:" % (ALL_CERTS.Get(cert),)
+        print "        %-*s  [%s]" % (self.max_pkg_len,
+                                      apk.package, apk.filename)
+      print
+
+  def CheckExternalSignatures(self):
+    for apk_filename, certname in self.certmap.iteritems():
+      if certname == "EXTERNAL":
+        # Apps marked EXTERNAL should be signed with the test key
+        # during development, then manually re-signed after
+        # predexopting.  Consider it an error if this app is now
+        # signed with any key that is present in our tree.
+        apk = self.apks_by_basename[apk_filename]
+        name = ALL_CERTS.Get(apk.cert)
+        if not name.startswith("unknown "):
+          Push(apk.filename)
+          AddProblem("hasn't been signed with EXTERNAL cert")
+          Pop()
+
+  def PrintCerts(self):
+    """Display a table of packages grouped by cert."""
+    by_cert = {}
+    for apk in self.apks.itervalues():
+      by_cert.setdefault(apk.cert, []).append((apk.package, apk))
+
+    order = [(-len(v), k) for (k, v) in by_cert.iteritems()]
+    order.sort()
+
+    for _, cert in order:
+      print "%s:" % (ALL_CERTS.Get(cert),)
+      apks = by_cert[cert]
+      apks.sort()
+      for _, apk in apks:
+        if apk.shared_uid:
+          print "  %-*s  %-*s  [%s]" % (self.max_fn_len, apk.filename,
+                                        self.max_pkg_len, apk.package,
+                                        apk.shared_uid)
+        else:
+          print "  %-*s  %-*s" % (self.max_fn_len, apk.filename,
+                                  self.max_pkg_len, apk.package)
+      print
+
+  def CompareWith(self, other):
+    """Look for instances where a given package that exists in both
+    self and other have different certs."""
+
+    all = set(self.apks.keys())
+    all.update(other.apks.keys())
+
+    max_pkg_len = max(self.max_pkg_len, other.max_pkg_len)
+
+    by_certpair = {}
+
+    for i in all:
+      if i in self.apks:
+        if i in other.apks:
+          # in both; should have the same cert
+          if self.apks[i].cert != other.apks[i].cert:
+            by_certpair.setdefault((other.apks[i].cert,
+                                    self.apks[i].cert), []).append(i)
+        else:
+          print "%s [%s]: new APK (not in comparison target_files)" % (
+              i, self.apks[i].filename)
+      else:
+        if i in other.apks:
+          print "%s [%s]: removed APK (only in comparison target_files)" % (
+              i, other.apks[i].filename)
+
+    if by_certpair:
+      AddProblem("some APKs changed certs")
+      Banner("APK signing differences")
+      for (old, new), packages in sorted(by_certpair.items()):
+        print "was", ALL_CERTS.Get(old)
+        print "now", ALL_CERTS.Get(new)
+        for i in sorted(packages):
+          old_fn = other.apks[i].filename
+          new_fn = self.apks[i].filename
+          if old_fn == new_fn:
+            print "  %-*s  [%s]" % (max_pkg_len, i, old_fn)
+          else:
+            print "  %-*s  [was: %s; now: %s]" % (max_pkg_len, i,
+                                                  old_fn, new_fn)
+        print
+
+
+def main(argv):
+  def option_handler(o, a):
+    if o in ("-c", "--compare_with"):
+      OPTIONS.compare_with = a
+    elif o in ("-l", "--local_cert_dirs"):
+      OPTIONS.local_cert_dirs = [i.strip() for i in a.split(",")]
+    elif o in ("-t", "--text"):
+      OPTIONS.text = True
+    else:
+      return False
+    return True
+
+  args = common.ParseOptions(argv, __doc__,
+                             extra_opts="c:l:t",
+                             extra_long_opts=["compare_with=",
+                                              "local_cert_dirs="],
+                             extra_option_handler=option_handler)
+
+  if len(args) != 1:
+    common.Usage(__doc__)
+    sys.exit(1)
+
+  ALL_CERTS.FindLocalCerts()
+
+  Push("input target_files:")
+  try:
+    target_files = TargetFiles()
+    target_files.LoadZipFile(args[0])
+  finally:
+    Pop()
+
+  compare_files = None
+  if OPTIONS.compare_with:
+    Push("comparison target_files:")
+    try:
+      compare_files = TargetFiles()
+      compare_files.LoadZipFile(OPTIONS.compare_with)
+    finally:
+      Pop()
+
+  if OPTIONS.text or not compare_files:
+    Banner("target files")
+    target_files.PrintCerts()
+  target_files.CheckSharedUids()
+  target_files.CheckExternalSignatures()
+  if compare_files:
+    if OPTIONS.text:
+      Banner("comparison files")
+      compare_files.PrintCerts()
+    target_files.CompareWith(compare_files)
+
+  if PROBLEMS:
+    print "%d problem(s) found:\n" % (len(PROBLEMS),)
+    for p in PROBLEMS:
+      print p
+    return 1
+
+  return 0
+
+
+if __name__ == '__main__':
+  try:
+    r = main(sys.argv[1:])
+    sys.exit(r)
+  except common.ExternalError, e:
+    print
+    print "   ERROR: %s" % (e,)
+    print
+    sys.exit(1)
diff --git a/build/tools/releasetools/common.py b/build/tools/releasetools/common.py
new file mode 100644 (file)
index 0000000..a236a12
--- /dev/null
@@ -0,0 +1,785 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import copy
+import errno
+import getopt
+import getpass
+import imp
+import os
+import re
+import sha
+import shutil
+import subprocess
+import sys
+import tempfile
+import threading
+import time
+import zipfile
+
+# missing in Python 2.4 and before
+if not hasattr(os, "SEEK_SET"):
+  os.SEEK_SET = 0
+
+class Options(object): pass
+OPTIONS = Options()
+OPTIONS.search_path = "out/host/linux-x86"
+OPTIONS.verbose = False
+OPTIONS.tempfiles = []
+OPTIONS.device_specific = None
+OPTIONS.extras = {}
+OPTIONS.info_dict = None
+
+
+# Values for "certificate" in apkcerts that mean special things.
+SPECIAL_CERT_STRINGS = ("PRESIGNED", "EXTERNAL")
+
+
+class ExternalError(RuntimeError): pass
+
+
+def Run(args, **kwargs):
+  """Create and return a subprocess.Popen object, printing the command
+  line on the terminal if -v was specified."""
+  if OPTIONS.verbose:
+    print "  running: ", " ".join(args)
+  return subprocess.Popen(args, **kwargs)
+
+
+def LoadInfoDict(zip):
+  """Read and parse the META/misc_info.txt key/value pairs from the
+  input target files and return a dict."""
+
+  d = {}
+  try:
+    for line in zip.read("META/misc_info.txt").split("\n"):
+      line = line.strip()
+      if not line or line.startswith("#"): continue
+      k, v = line.split("=", 1)
+      d[k] = v
+  except KeyError:
+    # ok if misc_info.txt doesn't exist
+    pass
+
+  # backwards compatibility: These values used to be in their own
+  # files.  Look for them, in case we're processing an old
+  # target_files zip.
+
+  if "mkyaffs2_extra_flags" not in d:
+    try:
+      d["mkyaffs2_extra_flags"] = zip.read("META/mkyaffs2-extra-flags.txt").strip()
+    except KeyError:
+      # ok if flags don't exist
+      pass
+
+  if "recovery_api_version" not in d:
+    try:
+      d["recovery_api_version"] = zip.read("META/recovery-api-version.txt").strip()
+    except KeyError:
+      raise ValueError("can't find recovery API version in input target-files")
+
+  if "tool_extensions" not in d:
+    try:
+      d["tool_extensions"] = zip.read("META/tool-extensions.txt").strip()
+    except KeyError:
+      # ok if extensions don't exist
+      pass
+
+  try:
+    data = zip.read("META/imagesizes.txt")
+    for line in data.split("\n"):
+      if not line: continue
+      name, value = line.split(" ", 1)
+      if not value: continue
+      if name == "blocksize":
+        d[name] = value
+      else:
+        d[name + "_size"] = value
+  except KeyError:
+    pass
+
+  def makeint(key):
+    if key in d:
+      d[key] = int(d[key], 0)
+
+  makeint("recovery_api_version")
+  makeint("blocksize")
+  makeint("system_size")
+  makeint("userdata_size")
+  makeint("recovery_size")
+  makeint("boot_size")
+
+  d["fstab"] = LoadRecoveryFSTab(zip)
+  if not d["fstab"]:
+    if "fs_type" not in d: d["fs_type"] = "yaffs2"
+    if "partition_type" not in d: d["partition_type"] = "MTD"
+
+  return d
+
+def LoadRecoveryFSTab(zip):
+  class Partition(object):
+    pass
+
+  try:
+    data = zip.read("RECOVERY/RAMDISK/etc/recovery.fstab")
+  except KeyError:
+    # older target-files that doesn't have a recovery.fstab; fall back
+    # to the fs_type and partition_type keys.
+    return
+
+  d = {}
+  for line in data.split("\n"):
+    line = line.strip()
+    if not line or line.startswith("#"): continue
+    pieces = line.split()
+    if not (3 <= len(pieces) <= 4):
+      raise ValueError("malformed recovery.fstab line: \"%s\"" % (line,))
+
+    p = Partition()
+    p.mount_point = pieces[0]
+    p.fs_type = pieces[1]
+    p.device = pieces[2]
+    if len(pieces) == 4:
+      p.device2 = pieces[3]
+    else:
+      p.device2 = None
+
+    d[p.mount_point] = p
+  return d
+
+
+def DumpInfoDict(d):
+  for k, v in sorted(d.items()):
+    print "%-25s = (%s) %s" % (k, type(v).__name__, v)
+
+def BuildAndAddBootableImage(sourcedir, targetname, output_zip, info_dict):
+  """Take a kernel, cmdline, and ramdisk directory from the input (in
+  'sourcedir'), and turn them into a boot image.  Put the boot image
+  into the output zip file under the name 'targetname'.  Returns
+  targetname on success or None on failure (if sourcedir does not
+  appear to contain files for the requested image)."""
+
+  print "creating %s..." % (targetname,)
+
+  img = BuildBootableImage(sourcedir)
+  if img is None:
+    return None
+
+  CheckSize(img, targetname, info_dict)
+  ZipWriteStr(output_zip, targetname, img)
+  return targetname
+
+def BuildBootableImage(sourcedir):
+  """Take a kernel, cmdline, and ramdisk directory from the input (in
+  'sourcedir'), and turn them into a boot image.  Return the image
+  data, or None if sourcedir does not appear to contains files for
+  building the requested image."""
+
+  if (not os.access(os.path.join(sourcedir, "RAMDISK"), os.F_OK) or
+      not os.access(os.path.join(sourcedir, "kernel"), os.F_OK)):
+    return None
+
+  ramdisk_img = tempfile.NamedTemporaryFile()
+  img = tempfile.NamedTemporaryFile()
+
+  p1 = Run(["mkbootfs", os.path.join(sourcedir, "RAMDISK")],
+           stdout=subprocess.PIPE)
+  p2 = Run(["minigzip"],
+           stdin=p1.stdout, stdout=ramdisk_img.file.fileno())
+
+  p2.wait()
+  p1.wait()
+  assert p1.returncode == 0, "mkbootfs of %s ramdisk failed" % (targetname,)
+  assert p2.returncode == 0, "minigzip of %s ramdisk failed" % (targetname,)
+
+  cmd = ["mkbootimg", "--kernel", os.path.join(sourcedir, "kernel")]
+
+  fn = os.path.join(sourcedir, "cmdline")
+  if os.access(fn, os.F_OK):
+    cmd.append("--cmdline")
+    cmd.append(open(fn).read().rstrip("\n"))
+
+  fn = os.path.join(sourcedir, "base")
+  if os.access(fn, os.F_OK):
+    cmd.append("--base")
+    cmd.append(open(fn).read().rstrip("\n"))
+
+  fn = os.path.join(sourcedir, "pagesize")
+  if os.access(fn, os.F_OK):
+    cmd.append("--pagesize")
+    cmd.append(open(fn).read().rstrip("\n"))
+
+  cmd.extend(["--ramdisk", ramdisk_img.name,
+              "--output", img.name])
+
+  p = Run(cmd, stdout=subprocess.PIPE)
+  p.communicate()
+  assert p.returncode == 0, "mkbootimg of %s image failed" % (
+      os.path.basename(sourcedir),)
+
+  img.seek(os.SEEK_SET, 0)
+  data = img.read()
+
+  ramdisk_img.close()
+  img.close()
+
+  return data
+
+
+def AddRecovery(output_zip, info_dict):
+  BuildAndAddBootableImage(os.path.join(OPTIONS.input_tmp, "RECOVERY"),
+                           "recovery.img", output_zip, info_dict)
+
+def AddBoot(output_zip, info_dict):
+  BuildAndAddBootableImage(os.path.join(OPTIONS.input_tmp, "BOOT"),
+                           "boot.img", output_zip, info_dict)
+
+def UnzipTemp(filename, pattern=None):
+  """Unzip the given archive into a temporary directory and return the name."""
+
+  tmp = tempfile.mkdtemp(prefix="targetfiles-")
+  OPTIONS.tempfiles.append(tmp)
+  cmd = ["unzip", "-o", "-q", filename, "-d", tmp]
+  if pattern is not None:
+    cmd.append(pattern)
+  p = Run(cmd, stdout=subprocess.PIPE)
+  p.communicate()
+  if p.returncode != 0:
+    raise ExternalError("failed to unzip input target-files \"%s\"" %
+                        (filename,))
+  return tmp
+
+
+def GetKeyPasswords(keylist):
+  """Given a list of keys, prompt the user to enter passwords for
+  those which require them.  Return a {key: password} dict.  password
+  will be None if the key has no password."""
+
+  no_passwords = []
+  need_passwords = []
+  devnull = open("/dev/null", "w+b")
+  for k in sorted(keylist):
+    # We don't need a password for things that aren't really keys.
+    if k in SPECIAL_CERT_STRINGS:
+      no_passwords.append(k)
+      continue
+
+    p = Run(["openssl", "pkcs8", "-in", k+".pk8",
+             "-inform", "DER", "-nocrypt"],
+            stdin=devnull.fileno(),
+            stdout=devnull.fileno(),
+            stderr=subprocess.STDOUT)
+    p.communicate()
+    if p.returncode == 0:
+      no_passwords.append(k)
+    else:
+      need_passwords.append(k)
+  devnull.close()
+
+  key_passwords = PasswordManager().GetPasswords(need_passwords)
+  key_passwords.update(dict.fromkeys(no_passwords, None))
+  return key_passwords
+
+
+def SignFile(input_name, output_name, key, password, align=None,
+             whole_file=False):
+  """Sign the input_name zip/jar/apk, producing output_name.  Use the
+  given key and password (the latter may be None if the key does not
+  have a password.
+
+  If align is an integer > 1, zipalign is run to align stored files in
+  the output zip on 'align'-byte boundaries.
+
+  If whole_file is true, use the "-w" option to SignApk to embed a
+  signature that covers the whole file in the archive comment of the
+  zip file.
+  """
+
+  if align == 0 or align == 1:
+    align = None
+
+  if align:
+    temp = tempfile.NamedTemporaryFile()
+    sign_name = temp.name
+  else:
+    sign_name = output_name
+
+  cmd = ["java", "-Xmx512m", "-jar",
+           os.path.join(OPTIONS.search_path, "framework", "signapk.jar")]
+  if whole_file:
+    cmd.append("-w")
+  cmd.extend([key + ".x509.pem", key + ".pk8",
+              input_name, sign_name])
+
+  p = Run(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+  if password is not None:
+    password += "\n"
+  p.communicate(password)
+  if p.returncode != 0:
+    raise ExternalError("signapk.jar failed: return code %s" % (p.returncode,))
+
+  if align:
+    p = Run(["zipalign", "-f", str(align), sign_name, output_name])
+    p.communicate()
+    if p.returncode != 0:
+      raise ExternalError("zipalign failed: return code %s" % (p.returncode,))
+    temp.close()
+
+
+def CheckSize(data, target, info_dict):
+  """Check the data string passed against the max size limit, if
+  any, for the given target.  Raise exception if the data is too big.
+  Print a warning if the data is nearing the maximum size."""
+
+  if target.endswith(".img"): target = target[:-4]
+  mount_point = "/" + target
+
+  if info_dict["fstab"]:
+    if mount_point == "/userdata": mount_point = "/data"
+    p = info_dict["fstab"][mount_point]
+    fs_type = p.fs_type
+    limit = info_dict.get(p.device + "_size", None)
+  else:
+    fs_type = info_dict.get("fs_type", None)
+    limit = info_dict.get(target + "_size", None)
+  if not fs_type or not limit: return
+
+  if fs_type == "yaffs2":
+    # image size should be increased by 1/64th to account for the
+    # spare area (64 bytes per 2k page)
+    limit = limit / 2048 * (2048+64)
+
+  size = len(data)
+  pct = float(size) * 100.0 / limit
+  msg = "%s size (%d) is %.2f%% of limit (%d)" % (target, size, pct, limit)
+  if pct >= 99.0:
+    raise ExternalError(msg)
+  elif pct >= 95.0:
+    print
+    print "  WARNING: ", msg
+    print
+  elif OPTIONS.verbose:
+    print "  ", msg
+
+
+def ReadApkCerts(tf_zip):
+  """Given a target_files ZipFile, parse the META/apkcerts.txt file
+  and return a {package: cert} dict."""
+  certmap = {}
+  for line in tf_zip.read("META/apkcerts.txt").split("\n"):
+    line = line.strip()
+    if not line: continue
+    m = re.match(r'^name="(.*)"\s+certificate="(.*)"\s+'
+                 r'private_key="(.*)"$', line)
+    if m:
+      name, cert, privkey = m.groups()
+      if cert in SPECIAL_CERT_STRINGS and not privkey:
+        certmap[name] = cert
+      elif (cert.endswith(".x509.pem") and
+            privkey.endswith(".pk8") and
+            cert[:-9] == privkey[:-4]):
+        certmap[name] = cert[:-9]
+      else:
+        raise ValueError("failed to parse line from apkcerts.txt:\n" + line)
+  return certmap
+
+
+COMMON_DOCSTRING = """
+  -p  (--path)  <dir>
+      Prepend <dir>/bin to the list of places to search for binaries
+      run by this script, and expect to find jars in <dir>/framework.
+
+  -s  (--device_specific) <file>
+      Path to the python module containing device-specific
+      releasetools code.
+
+  -x  (--extra)  <key=value>
+      Add a key/value pair to the 'extras' dict, which device-specific
+      extension code may look at.
+
+  -v  (--verbose)
+      Show command lines being executed.
+
+  -h  (--help)
+      Display this usage message and exit.
+"""
+
+def Usage(docstring):
+  print docstring.rstrip("\n")
+  print COMMON_DOCSTRING
+
+
+def ParseOptions(argv,
+                 docstring,
+                 extra_opts="", extra_long_opts=(),
+                 extra_option_handler=None):
+  """Parse the options in argv and return any arguments that aren't
+  flags.  docstring is the calling module's docstring, to be displayed
+  for errors and -h.  extra_opts and extra_long_opts are for flags
+  defined by the caller, which are processed by passing them to
+  extra_option_handler."""
+
+  try:
+    opts, args = getopt.getopt(
+        argv, "hvp:s:x:" + extra_opts,
+        ["help", "verbose", "path=", "device_specific=", "extra="] +
+          list(extra_long_opts))
+  except getopt.GetoptError, err:
+    Usage(docstring)
+    print "**", str(err), "**"
+    sys.exit(2)
+
+  path_specified = False
+
+  for o, a in opts:
+    if o in ("-h", "--help"):
+      Usage(docstring)
+      sys.exit()
+    elif o in ("-v", "--verbose"):
+      OPTIONS.verbose = True
+    elif o in ("-p", "--path"):
+      OPTIONS.search_path = a
+    elif o in ("-s", "--device_specific"):
+      OPTIONS.device_specific = a
+    elif o in ("-x", "--extra"):
+      key, value = a.split("=", 1)
+      OPTIONS.extras[key] = value
+    else:
+      if extra_option_handler is None or not extra_option_handler(o, a):
+        assert False, "unknown option \"%s\"" % (o,)
+
+  os.environ["PATH"] = (os.path.join(OPTIONS.search_path, "bin") +
+                        os.pathsep + os.environ["PATH"])
+
+  return args
+
+
+def Cleanup():
+  for i in OPTIONS.tempfiles:
+    if os.path.isdir(i):
+      shutil.rmtree(i)
+    else:
+      os.remove(i)
+
+
+class PasswordManager(object):
+  def __init__(self):
+    self.editor = os.getenv("EDITOR", None)
+    self.pwfile = os.getenv("ANDROID_PW_FILE", None)
+
+  def GetPasswords(self, items):
+    """Get passwords corresponding to each string in 'items',
+    returning a dict.  (The dict may have keys in addition to the
+    values in 'items'.)
+
+    Uses the passwords in $ANDROID_PW_FILE if available, letting the
+    user edit that file to add more needed passwords.  If no editor is
+    available, or $ANDROID_PW_FILE isn't define, prompts the user
+    interactively in the ordinary way.
+    """
+
+    current = self.ReadFile()
+
+    first = True
+    while True:
+      missing = []
+      for i in items:
+        if i not in current or not current[i]:
+          missing.append(i)
+      # Are all the passwords already in the file?
+      if not missing: return current
+
+      for i in missing:
+        current[i] = ""
+
+      if not first:
+        print "key file %s still missing some passwords." % (self.pwfile,)
+        answer = raw_input("try to edit again? [y]> ").strip()
+        if answer and answer[0] not in 'yY':
+          raise RuntimeError("key passwords unavailable")
+      first = False
+
+      current = self.UpdateAndReadFile(current)
+
+  def PromptResult(self, current):
+    """Prompt the user to enter a value (password) for each key in
+    'current' whose value is fales.  Returns a new dict with all the
+    values.
+    """
+    result = {}
+    for k, v in sorted(current.iteritems()):
+      if v:
+        result[k] = v
+      else:
+        while True:
+          result[k] = getpass.getpass("Enter password for %s key> "
+                                      % (k,)).strip()
+          if result[k]: break
+    return result
+
+  def UpdateAndReadFile(self, current):
+    if not self.editor or not self.pwfile:
+      return self.PromptResult(current)
+
+    f = open(self.pwfile, "w")
+    os.chmod(self.pwfile, 0600)
+    f.write("# Enter key passwords between the [[[ ]]] brackets.\n")
+    f.write("# (Additional spaces are harmless.)\n\n")
+
+    first_line = None
+    sorted = [(not v, k, v) for (k, v) in current.iteritems()]
+    sorted.sort()
+    for i, (_, k, v) in enumerate(sorted):
+      f.write("[[[  %s  ]]] %s\n" % (v, k))
+      if not v and first_line is None:
+        # position cursor on first line with no password.
+        first_line = i + 4
+    f.close()
+
+    p = Run([self.editor, "+%d" % (first_line,), self.pwfile])
+    _, _ = p.communicate()
+
+    return self.ReadFile()
+
+  def ReadFile(self):
+    result = {}
+    if self.pwfile is None: return result
+    try:
+      f = open(self.pwfile, "r")
+      for line in f:
+        line = line.strip()
+        if not line or line[0] == '#': continue
+        m = re.match(r"^\[\[\[\s*(.*?)\s*\]\]\]\s*(\S+)$", line)
+        if not m:
+          print "failed to parse password file: ", line
+        else:
+          result[m.group(2)] = m.group(1)
+      f.close()
+    except IOError, e:
+      if e.errno != errno.ENOENT:
+        print "error reading password file: ", str(e)
+    return result
+
+
+def ZipWriteStr(zip, filename, data, perms=0644):
+  # use a fixed timestamp so the output is repeatable.
+  zinfo = zipfile.ZipInfo(filename=filename,
+                          date_time=(2009, 1, 1, 0, 0, 0))
+  zinfo.compress_type = zip.compression
+  zinfo.external_attr = perms << 16
+  zip.writestr(zinfo, data)
+
+
+class DeviceSpecificParams(object):
+  module = None
+  def __init__(self, **kwargs):
+    """Keyword arguments to the constructor become attributes of this
+    object, which is passed to all functions in the device-specific
+    module."""
+    for k, v in kwargs.iteritems():
+      setattr(self, k, v)
+    self.extras = OPTIONS.extras
+
+    if self.module is None:
+      path = OPTIONS.device_specific
+      if not path: return
+      try:
+        if os.path.isdir(path):
+          info = imp.find_module("releasetools", [path])
+        else:
+          d, f = os.path.split(path)
+          b, x = os.path.splitext(f)
+          if x == ".py":
+            f = b
+          info = imp.find_module(f, [d])
+        self.module = imp.load_module("device_specific", *info)
+      except ImportError:
+        print "unable to load device-specific module; assuming none"
+
+  def _DoCall(self, function_name, *args, **kwargs):
+    """Call the named function in the device-specific module, passing
+    the given args and kwargs.  The first argument to the call will be
+    the DeviceSpecific object itself.  If there is no module, or the
+    module does not define the function, return the value of the
+    'default' kwarg (which itself defaults to None)."""
+    if self.module is None or not hasattr(self.module, function_name):
+      return kwargs.get("default", None)
+    return getattr(self.module, function_name)(*((self,) + args), **kwargs)
+
+  def FullOTA_Assertions(self):
+    """Called after emitting the block of assertions at the top of a
+    full OTA package.  Implementations can add whatever additional
+    assertions they like."""
+    return self._DoCall("FullOTA_Assertions")
+
+  def FullOTA_InstallEnd(self):
+    """Called at the end of full OTA installation; typically this is
+    used to install the image for the device's baseband processor."""
+    return self._DoCall("FullOTA_InstallEnd")
+
+  def IncrementalOTA_Assertions(self):
+    """Called after emitting the block of assertions at the top of an
+    incremental OTA package.  Implementations can add whatever
+    additional assertions they like."""
+    return self._DoCall("IncrementalOTA_Assertions")
+
+  def IncrementalOTA_VerifyEnd(self):
+    """Called at the end of the verification phase of incremental OTA
+    installation; additional checks can be placed here to abort the
+    script before any changes are made."""
+    return self._DoCall("IncrementalOTA_VerifyEnd")
+
+  def IncrementalOTA_InstallEnd(self):
+    """Called at the end of incremental OTA installation; typically
+    this is used to install the image for the device's baseband
+    processor."""
+    return self._DoCall("IncrementalOTA_InstallEnd")
+
+class File(object):
+  def __init__(self, name, data):
+    self.name = name
+    self.data = data
+    self.size = len(data)
+    self.sha1 = sha.sha(data).hexdigest()
+
+  def WriteToTemp(self):
+    t = tempfile.NamedTemporaryFile()
+    t.write(self.data)
+    t.flush()
+    return t
+
+  def AddToZip(self, z):
+    ZipWriteStr(z, self.name, self.data)
+
+DIFF_PROGRAM_BY_EXT = {
+    ".gz" : "imgdiff",
+    ".zip" : ["imgdiff", "-z"],
+    ".jar" : ["imgdiff", "-z"],
+    ".apk" : ["imgdiff", "-z"],
+    ".img" : "imgdiff",
+    }
+
+class Difference(object):
+  def __init__(self, tf, sf):
+    self.tf = tf
+    self.sf = sf
+    self.patch = None
+
+  def ComputePatch(self):
+    """Compute the patch (as a string of data) needed to turn sf into
+    tf.  Returns the same tuple as GetPatch()."""
+
+    tf = self.tf
+    sf = self.sf
+
+    ext = os.path.splitext(tf.name)[1]
+    diff_program = DIFF_PROGRAM_BY_EXT.get(ext, "bsdiff")
+
+    ttemp = tf.WriteToTemp()
+    stemp = sf.WriteToTemp()
+
+    ext = os.path.splitext(tf.name)[1]
+
+    try:
+      ptemp = tempfile.NamedTemporaryFile()
+      if isinstance(diff_program, list):
+        cmd = copy.copy(diff_program)
+      else:
+        cmd = [diff_program]
+      cmd.append(stemp.name)
+      cmd.append(ttemp.name)
+      cmd.append(ptemp.name)
+      p = Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+      _, err = p.communicate()
+      if err or p.returncode != 0:
+        print "WARNING: failure running %s:\n%s\n" % (diff_program, err)
+        return None
+      diff = ptemp.read()
+    finally:
+      ptemp.close()
+      stemp.close()
+      ttemp.close()
+
+    self.patch = diff
+    return self.tf, self.sf, self.patch
+
+
+  def GetPatch(self):
+    """Return a tuple (target_file, source_file, patch_data).
+    patch_data may be None if ComputePatch hasn't been called, or if
+    computing the patch failed."""
+    return self.tf, self.sf, self.patch
+
+
+def ComputeDifferences(diffs):
+  """Call ComputePatch on all the Difference objects in 'diffs'."""
+  print len(diffs), "diffs to compute"
+
+  # Do the largest files first, to try and reduce the long-pole effect.
+  by_size = [(i.tf.size, i) for i in diffs]
+  by_size.sort(reverse=True)
+  by_size = [i[1] for i in by_size]
+
+  lock = threading.Lock()
+  diff_iter = iter(by_size)   # accessed under lock
+
+  def worker():
+    try:
+      lock.acquire()
+      for d in diff_iter:
+        lock.release()
+        start = time.time()
+        d.ComputePatch()
+        dur = time.time() - start
+        lock.acquire()
+
+        tf, sf, patch = d.GetPatch()
+        if sf.name == tf.name:
+          name = tf.name
+        else:
+          name = "%s (%s)" % (tf.name, sf.name)
+        if patch is None:
+          print "patching failed!                                  %s" % (name,)
+        else:
+          print "%8.2f sec %8d / %8d bytes (%6.2f%%) %s" % (
+              dur, len(patch), tf.size, 100.0 * len(patch) / tf.size, name)
+      lock.release()
+    except Exception, e:
+      print e
+      raise
+
+  # start worker threads; wait for them all to finish.
+  threads = [threading.Thread(target=worker)
+             for i in range(OPTIONS.worker_threads)]
+  for th in threads:
+    th.start()
+  while threads:
+    threads.pop().join()
+
+
+# map recovery.fstab's fs_types to mount/format "partition types"
+PARTITION_TYPES = { "yaffs2": "MTD", "mtd": "MTD",
+                    "ext4": "EMMC", "emmc": "EMMC" }
+
+def GetTypeAndDevice(mount_point, info):
+  fstab = info["fstab"]
+  if fstab:
+    return PARTITION_TYPES[fstab[mount_point].fs_type], fstab[mount_point].device
+  else:
+    devices = {"/boot": "boot",
+               "/recovery": "recovery",
+               "/radio": "radio",
+               "/data": "userdata",
+               "/cache": "cache"}
+    return info["partition_type"], info.get("partition_path", "") + devices[mount_point]
diff --git a/build/tools/releasetools/edify_generator.py b/build/tools/releasetools/edify_generator.py
new file mode 100644 (file)
index 0000000..756d673
--- /dev/null
@@ -0,0 +1,297 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import re
+
+import common
+
+class EdifyGenerator(object):
+  """Class to generate scripts in the 'edify' recovery script language
+  used from donut onwards."""
+
+  def __init__(self, version, info):
+    self.script = []
+    self.mounts = set()
+    self.version = version
+    self.info = info
+
+  def MakeTemporary(self):
+    """Make a temporary script object whose commands can latter be
+    appended to the parent script with AppendScript().  Used when the
+    caller wants to generate script commands out-of-order."""
+    x = EdifyGenerator(self.version, self.info)
+    x.mounts = self.mounts
+    return x
+
+  @staticmethod
+  def _WordWrap(cmd, linelen=80):
+    """'cmd' should be a function call with null characters after each
+    parameter (eg, "somefun(foo,\0bar,\0baz)").  This function wraps cmd
+    to a given line length, replacing nulls with spaces and/or newlines
+    to format it nicely."""
+    indent = cmd.index("(")+1
+    out = []
+    first = True
+    x = re.compile("^(.{,%d})\0" % (linelen-indent,))
+    while True:
+      if not first:
+        out.append(" " * indent)
+      first = False
+      m = x.search(cmd)
+      if not m:
+        parts = cmd.split("\0", 1)
+        out.append(parts[0]+"\n")
+        if len(parts) == 1:
+          break
+        else:
+          cmd = parts[1]
+          continue
+      out.append(m.group(1)+"\n")
+      cmd = cmd[m.end():]
+
+    return "".join(out).replace("\0", " ").rstrip("\n")
+
+  def AppendScript(self, other):
+    """Append the contents of another script (which should be created
+    with temporary=True) to this one."""
+    self.script.extend(other.script)
+
+  def AssertSomeFingerprint(self, *fp):
+    """Assert that the current system build fingerprint is one of *fp."""
+    if not fp:
+      raise ValueError("must specify some fingerprints")
+    cmd = ('assert(' +
+           ' ||\0'.join([('file_getprop("/system/build.prop", '
+                         '"ro.build.fingerprint") == "%s"')
+                        % i for i in fp]) +
+           ');')
+    self.script.append(self._WordWrap(cmd))
+
+  def AssertOlderBuild(self, timestamp):
+    """Assert that the build on the device is older (or the same as)
+    the given timestamp."""
+    self.script.append(('assert(!less_than_int(%s, '
+                        'getprop("ro.build.date.utc")));') % (timestamp,))
+
+  def AssertDevice(self, device):
+    """Assert that the device identifier is the given string."""
+    cmd = ('assert(getprop("ro.product.device") == "%s" ||\0'
+           'getprop("ro.build.product") == "%s");' % (device, device))
+    self.script.append(self._WordWrap(cmd))
+
+  def AssertSomeBootloader(self, *bootloaders):
+    """Asert that the bootloader version is one of *bootloaders."""
+    cmd = ("assert(" +
+           " ||\0".join(['getprop("ro.bootloader") == "%s"' % (b,)
+                         for b in bootloaders]) +
+           ");")
+    self.script.append(self._WordWrap(cmd))
+
+  def ShowProgress(self, frac, dur):
+    """Update the progress bar, advancing it over 'frac' over the next
+    'dur' seconds.  'dur' may be zero to advance it via SetProgress
+    commands instead of by time."""
+    self.script.append("show_progress(%f, %d);" % (frac, int(dur)))
+
+  def SetProgress(self, frac):
+    """Set the position of the progress bar within the chunk defined
+    by the most recent ShowProgress call.  'frac' should be in
+    [0,1]."""
+    self.script.append("set_progress(%f);" % (frac,))
+
+  def PatchCheck(self, filename, *sha1):
+    """Check that the given file (or MTD reference) has one of the
+    given *sha1 hashes, checking the version saved in cache if the
+    file does not match."""
+    self.script.append('assert(apply_patch_check("%s"' % (filename,) +
+                       "".join([', "%s"' % (i,) for i in sha1]) +
+                       '));')
+
+  def FileCheck(self, filename, *sha1):
+    """Check that the given file (or MTD reference) has one of the
+    given *sha1 hashes."""
+    self.script.append('assert(sha1_check(read_file("%s")' % (filename,) +
+                       "".join([', "%s"' % (i,) for i in sha1]) +
+                       '));')
+
+  def CacheFreeSpaceCheck(self, amount):
+    """Check that there's at least 'amount' space that can be made
+    available on /cache."""
+    self.script.append("assert(apply_patch_space(%d));" % (amount,))
+
+  def Mount(self, mount_point):
+    """Mount the partition with the given mount_point."""
+    fstab = self.info.get("fstab", None)
+    if fstab:
+      p = fstab[mount_point]
+      self.script.append('mount("%s", "%s", "%s", "%s");' %
+                         (p.fs_type, common.PARTITION_TYPES[p.fs_type],
+                          p.device, p.mount_point))
+      self.mounts.add(p.mount_point)
+    else:
+      what = mount_point.lstrip("/")
+      what = self.info.get("partition_path", "") + what
+      self.script.append('mount("%s", "%s", "%s", "%s");' %
+                         (self.info["fs_type"], self.info["partition_type"],
+                          what, mount_point))
+      self.mounts.add(mount_point)
+
+  def UnpackPackageDir(self, src, dst):
+    """Unpack a given directory from the OTA package into the given
+    destination directory."""
+    self.script.append('package_extract_dir("%s", "%s");' % (src, dst))
+
+  def Comment(self, comment):
+    """Write a comment into the update script."""
+    self.script.append("")
+    for i in comment.split("\n"):
+      self.script.append("# " + i)
+    self.script.append("")
+
+  def Print(self, message):
+    """Log a message to the screen (if the logs are visible)."""
+    self.script.append('ui_print("%s");' % (message,))
+
+  def FormatPartition(self, partition):
+    """Format the given partition, specified by its mount point (eg,
+    "/system")."""
+
+    fstab = self.info.get("fstab", None)
+    if fstab:
+      p = fstab[partition]
+      self.script.append('format("%s", "%s", "%s");' %
+                         (p.fs_type, common.PARTITION_TYPES[p.fs_type], p.device))
+    else:
+      # older target-files without per-partition types
+      partition = self.info.get("partition_path", "") + partition
+      self.script.append('format("%s", "%s", "%s");' %
+                         (self.info["fs_type"], self.info["partition_type"],
+                          partition))
+
+  def DeleteFiles(self, file_list):
+    """Delete all files in file_list."""
+    if not file_list: return
+    cmd = "delete(" + ",\0".join(['"%s"' % (i,) for i in file_list]) + ");"
+    self.script.append(self._WordWrap(cmd))
+
+  def ApplyPatch(self, srcfile, tgtfile, tgtsize, tgtsha1, *patchpairs):
+    """Apply binary patches (in *patchpairs) to the given srcfile to
+    produce tgtfile (which may be "-" to indicate overwriting the
+    source file."""
+    if len(patchpairs) % 2 != 0 or len(patchpairs) == 0:
+      raise ValueError("bad patches given to ApplyPatch")
+    cmd = ['apply_patch("%s",\0"%s",\0%s,\0%d'
+           % (srcfile, tgtfile, tgtsha1, tgtsize)]
+    for i in range(0, len(patchpairs), 2):
+      cmd.append(',\0%s, package_extract_file("%s")' % patchpairs[i:i+2])
+    cmd.append(');')
+    cmd = "".join(cmd)
+    self.script.append(self._WordWrap(cmd))
+
+  def WriteFirmwareImage(self, kind, fn):
+    """Arrange to update the given firmware image (kind must be
+    "hboot" or "radio") when recovery finishes."""
+    if self.version == 1:
+      self.script.append(
+          ('assert(package_extract_file("%(fn)s", "/tmp/%(kind)s.img"),\n'
+           '       write_firmware_image("/tmp/%(kind)s.img", "%(kind)s"));')
+          % {'kind': kind, 'fn': fn})
+    else:
+      self.script.append(
+          'write_firmware_image("PACKAGE:%s", "%s");' % (fn, kind))
+
+  def WriteRawImage(self, mount_point, fn):
+    """Write the given package file into the partition for the given
+    mount point."""
+
+    fstab = self.info["fstab"]
+    if fstab:
+      p = fstab[mount_point]
+      partition_type = common.PARTITION_TYPES[p.fs_type]
+      args = {'device': p.device, 'fn': fn}
+      if partition_type == "MTD":
+        self.script.append(
+            ('assert(package_extract_file("%(fn)s", "/tmp/%(device)s.img"),\n'
+             '       write_raw_image("/tmp/%(device)s.img", "%(device)s"),\n'
+             '       delete("/tmp/%(device)s.img"));') % args)
+      elif partition_type == "EMMC":
+        self.script.append(
+            'package_extract_file("%(fn)s", "%(device)s");' % args)
+      else:
+        raise ValueError("don't know how to write \"%s\" partitions" % (p.fs_type,))
+    else:
+      # backward compatibility with older target-files that lack recovery.fstab
+      if self.info["partition_type"] == "MTD":
+        self.script.append(
+            ('assert(package_extract_file("%(fn)s", "/tmp/%(partition)s.img"),\n'
+             '       write_raw_image("/tmp/%(partition)s.img", "%(partition)s"),\n'
+             '       delete("/tmp/%(partition)s.img"));')
+            % {'partition': partition, 'fn': fn})
+      elif self.info["partition_type"] == "EMMC":
+        self.script.append(
+            ('package_extract_file("%(fn)s", "%(dir)s%(partition)s");')
+            % {'partition': partition, 'fn': fn,
+               'dir': self.info.get("partition_path", ""),
+               })
+      else:
+        raise ValueError("don't know how to write \"%s\" partitions" %
+                         (self.info["partition_type"],))
+
+  def SetPermissions(self, fn, uid, gid, mode):
+    """Set file ownership and permissions."""
+    self.script.append('set_perm(%d, %d, 0%o, "%s");' % (uid, gid, mode, fn))
+
+  def SetPermissionsRecursive(self, fn, uid, gid, dmode, fmode):
+    """Recursively set path ownership and permissions."""
+    self.script.append('set_perm_recursive(%d, %d, 0%o, 0%o, "%s");'
+                       % (uid, gid, dmode, fmode, fn))
+
+  def MakeSymlinks(self, symlink_list):
+    """Create symlinks, given a list of (dest, link) pairs."""
+    by_dest = {}
+    for d, l in symlink_list:
+      by_dest.setdefault(d, []).append(l)
+
+    for dest, links in sorted(by_dest.iteritems()):
+      cmd = ('symlink("%s", ' % (dest,) +
+             ",\0".join(['"' + i + '"' for i in sorted(links)]) + ");")
+      self.script.append(self._WordWrap(cmd))
+
+  def AppendExtra(self, extra):
+    """Append text verbatim to the output script."""
+    self.script.append(extra)
+
+  def UnmountAll(self):
+    for p in sorted(self.mounts):
+      self.script.append('unmount("%s");' % (p,))
+    self.mounts = set()
+
+  def AddToZip(self, input_zip, output_zip, input_path=None):
+    """Write the accumulated script to the output_zip file.  input_zip
+    is used as the source for the 'updater' binary needed to run
+    script.  If input_path is not None, it will be used as a local
+    path for the binary instead of input_zip."""
+
+    self.UnmountAll()
+
+    common.ZipWriteStr(output_zip, "META-INF/com/google/android/updater-script",
+                       "\n".join(self.script) + "\n")
+
+    if input_path is None:
+      data = input_zip.read("OTA/bin/updater")
+    else:
+      data = open(os.path.join(input_path, "updater")).read()
+    common.ZipWriteStr(output_zip, "META-INF/com/google/android/update-binary",
+                       data, perms=0755)
diff --git a/build/tools/releasetools/img_from_target_files b/build/tools/releasetools/img_from_target_files
new file mode 100644 (file)
index 0000000..0139916
--- /dev/null
@@ -0,0 +1,196 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Given a target-files zipfile, produces an image zipfile suitable for
+use with 'fastboot update'.
+
+Usage:  img_from_target_files [flags] input_target_files output_image_zip
+
+  -b  (--board_config)  <file>
+      Deprecated.
+
+"""
+
+import sys
+
+if sys.hexversion < 0x02040000:
+  print >> sys.stderr, "Python 2.4 or newer is required."
+  sys.exit(1)
+
+import errno
+import os
+import re
+import shutil
+import subprocess
+import tempfile
+import zipfile
+
+# missing in Python 2.4 and before
+if not hasattr(os, "SEEK_SET"):
+  os.SEEK_SET = 0
+
+import common
+
+OPTIONS = common.OPTIONS
+
+def AddUserdata(output_zip):
+  """Create an empty userdata image and store it in output_zip."""
+
+  print "creating userdata.img..."
+
+  # The name of the directory it is making an image out of matters to
+  # mkyaffs2image.  So we create a temp dir, and within it we create an
+  # empty dir named "data", and build the image from that.
+  temp_dir = tempfile.mkdtemp()
+  user_dir = os.path.join(temp_dir, "data")
+  os.mkdir(user_dir)
+  img = tempfile.NamedTemporaryFile()
+
+  build_command = []
+  fstab = OPTIONS.info_dict["fstab"]
+  if fstab and fstab["/data"].fs_type.startswith("ext"):
+    build_command = ["mkuserimg.sh"]
+    if "extfs_sparse_flag" in OPTIONS.info_dict:
+      build_command.append(OPTIONS.info_dict["extfs_sparse_flag"])
+    build_command.extend([user_dir, img.name,
+                     fstab["/data"].fs_type, "data"])
+    if "userdata_size" in OPTIONS.info_dict:
+      build_command.append(str(OPTIONS.info_dict["userdata_size"]))
+  else:
+    build_command = ["mkyaffs2image", "-f"]
+    extra = OPTIONS.info_dict.get("mkyaffs2_extra_flags", None)
+    if extra:
+      build_command.extend(extra.split())
+    build_command.append(user_dir)
+    build_command.append(img.name)
+
+  p = common.Run(build_command)
+  p.communicate()
+  assert p.returncode == 0, "build userdata.img image failed"
+
+  common.CheckSize(img.name, "userdata.img", OPTIONS.info_dict)
+  output_zip.write(img.name, "userdata.img")
+  img.close()
+  os.rmdir(user_dir)
+  os.rmdir(temp_dir)
+
+
+def AddSystem(output_zip):
+  """Turn the contents of SYSTEM into a system image and store it in
+  output_zip."""
+
+  print "creating system.img..."
+
+  img = tempfile.NamedTemporaryFile()
+
+  # The name of the directory it is making an image out of matters to
+  # mkyaffs2image.  It wants "system" but we have a directory named
+  # "SYSTEM", so create a symlink.
+  try:
+    os.symlink(os.path.join(OPTIONS.input_tmp, "SYSTEM"),
+               os.path.join(OPTIONS.input_tmp, "system"))
+  except OSError, e:
+      # bogus error on my mac version?
+      #   File "./build/tools/releasetools/img_from_target_files", line 86, in AddSystem
+      #     os.path.join(OPTIONS.input_tmp, "system"))
+      # OSError: [Errno 17] File exists
+    if (e.errno == errno.EEXIST):
+      pass
+
+  build_command = []
+  fstab = OPTIONS.info_dict["fstab"]
+  if fstab and fstab["/system"].fs_type.startswith("ext"):
+
+    build_command = ["mkuserimg.sh"]
+    if "extfs_sparse_flag" in OPTIONS.info_dict:
+      build_command.append(OPTIONS.info_dict["extfs_sparse_flag"])
+    build_command.extend([os.path.join(OPTIONS.input_tmp, "system"), img.name,
+                     fstab["/system"].fs_type, "system"])
+    if "system_size" in OPTIONS.info_dict:
+      build_command.append(str(OPTIONS.info_dict["system_size"]))
+  else:
+    build_command = ["mkyaffs2image", "-f"]
+    extra = OPTIONS.info_dict.get("mkyaffs2_extra_flags", None)
+    if extra:
+      build_command.extend(extra.split())
+    build_command.append(os.path.join(OPTIONS.input_tmp, "system"))
+    build_command.append(img.name)
+
+  p = common.Run(build_command)
+  p.communicate()
+  assert p.returncode == 0, "build system.img image failed"
+
+  img.seek(os.SEEK_SET, 0)
+  data = img.read()
+  img.close()
+
+  common.CheckSize(data, "system.img", OPTIONS.info_dict)
+  common.ZipWriteStr(output_zip, "system.img", data)
+
+
+def CopyInfo(output_zip):
+  """Copy the android-info.txt file from the input to the output."""
+  output_zip.write(os.path.join(OPTIONS.input_tmp, "OTA", "android-info.txt"),
+                   "android-info.txt")
+
+
+def main(argv):
+
+  def option_handler(o, a):
+    if o in ("-b", "--board_config"):
+      pass       # deprecated
+    else:
+      return False
+    return True
+
+  args = common.ParseOptions(argv, __doc__,
+                             extra_opts="b:",
+                             extra_long_opts=["board_config="],
+                             extra_option_handler=option_handler)
+
+  if len(args) != 2:
+    common.Usage(__doc__)
+    sys.exit(1)
+
+  OPTIONS.input_tmp = common.UnzipTemp(args[0])
+
+  input_zip = zipfile.ZipFile(args[0], "r")
+  OPTIONS.info_dict = common.LoadInfoDict(input_zip)
+
+  output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
+
+  common.AddBoot(output_zip, OPTIONS.info_dict)
+  common.AddRecovery(output_zip, OPTIONS.info_dict)
+  AddSystem(output_zip)
+  AddUserdata(output_zip)
+  CopyInfo(output_zip)
+
+  print "cleaning up..."
+  output_zip.close()
+  shutil.rmtree(OPTIONS.input_tmp)
+
+  print "done."
+
+
+if __name__ == '__main__':
+  try:
+    main(sys.argv[1:])
+  except common.ExternalError, e:
+    print
+    print "   ERROR: %s" % (e,)
+    print
+    sys.exit(1)
diff --git a/build/tools/releasetools/ota_from_target_files b/build/tools/releasetools/ota_from_target_files
new file mode 100644 (file)
index 0000000..aa691b4
--- /dev/null
@@ -0,0 +1,789 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Given a target-files zipfile, produces an OTA package that installs
+that build.  An incremental OTA is produced if -i is given, otherwise
+a full OTA is produced.
+
+Usage:  ota_from_target_files [flags] input_target_files output_ota_package
+
+  -b  (--board_config)  <file>
+      Deprecated.
+
+  -k  (--package_key)  <key>
+      Key to use to sign the package (default is
+      "build/target/product/security/testkey").
+
+  -i  (--incremental_from)  <file>
+      Generate an incremental OTA using the given target-files zip as
+      the starting build.
+
+  -w  (--wipe_user_data)
+      Generate an OTA package that will wipe the user data partition
+      when installed.
+
+  -n  (--no_prereq)
+      Omit the timestamp prereq check normally included at the top of
+      the build scripts (used for developer OTA packages which
+      legitimately need to go back and forth).
+
+  -e  (--extra_script)  <file>
+      Insert the contents of file at the end of the update script.
+
+"""
+
+import sys
+
+if sys.hexversion < 0x02040000:
+  print >> sys.stderr, "Python 2.4 or newer is required."
+  sys.exit(1)
+
+import copy
+import errno
+import os
+import re
+import sha
+import subprocess
+import tempfile
+import time
+import zipfile
+
+import common
+import edify_generator
+
+OPTIONS = common.OPTIONS
+OPTIONS.package_key = "build/target/product/security/testkey"
+OPTIONS.incremental_source = None
+OPTIONS.require_verbatim = set()
+OPTIONS.prohibit_verbatim = set(("system/build.prop",))
+OPTIONS.patch_threshold = 0.95
+OPTIONS.wipe_user_data = False
+OPTIONS.omit_prereq = False
+OPTIONS.extra_script = None
+OPTIONS.worker_threads = 3
+
+def MostPopularKey(d, default):
+  """Given a dict, return the key corresponding to the largest
+  value.  Returns 'default' if the dict is empty."""
+  x = [(v, k) for (k, v) in d.iteritems()]
+  if not x: return default
+  x.sort()
+  return x[-1][1]
+
+
+def IsSymlink(info):
+  """Return true if the zipfile.ZipInfo object passed in represents a
+  symlink."""
+  return (info.external_attr >> 16) == 0120777
+
+
+class Item:
+  """Items represent the metadata (user, group, mode) of files and
+  directories in the system image."""
+  ITEMS = {}
+  def __init__(self, name, dir=False):
+    self.name = name
+    self.uid = None
+    self.gid = None
+    self.mode = None
+    self.dir = dir
+
+    if name:
+      self.parent = Item.Get(os.path.dirname(name), dir=True)
+      self.parent.children.append(self)
+    else:
+      self.parent = None
+    if dir:
+      self.children = []
+
+  def Dump(self, indent=0):
+    if self.uid is not None:
+      print "%s%s %d %d %o" % ("  "*indent, self.name, self.uid, self.gid, self.mode)
+    else:
+      print "%s%s %s %s %s" % ("  "*indent, self.name, self.uid, self.gid, self.mode)
+    if self.dir:
+      print "%s%s" % ("  "*indent, self.descendants)
+      print "%s%s" % ("  "*indent, self.best_subtree)
+      for i in self.children:
+        i.Dump(indent=indent+1)
+
+  @classmethod
+  def Get(cls, name, dir=False):
+    if name not in cls.ITEMS:
+      cls.ITEMS[name] = Item(name, dir=dir)
+    return cls.ITEMS[name]
+
+  @classmethod
+  def GetMetadata(cls, input_zip):
+
+    try:
+      # See if the target_files contains a record of what the uid,
+      # gid, and mode is supposed to be.
+      output = input_zip.read("META/filesystem_config.txt")
+    except KeyError:
+      # Run the external 'fs_config' program to determine the desired
+      # uid, gid, and mode for every Item object.  Note this uses the
+      # one in the client now, which might not be the same as the one
+      # used when this target_files was built.
+      p = common.Run(["fs_config"], stdin=subprocess.PIPE,
+                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+      suffix = { False: "", True: "/" }
+      input = "".join(["%s%s\n" % (i.name, suffix[i.dir])
+                       for i in cls.ITEMS.itervalues() if i.name])
+      output, error = p.communicate(input)
+      assert not error
+
+    for line in output.split("\n"):
+      if not line: continue
+      name, uid, gid, mode = line.split()
+      i = cls.ITEMS.get(name, None)
+      if i is not None:
+        i.uid = int(uid)
+        i.gid = int(gid)
+        i.mode = int(mode, 8)
+        if i.dir:
+          i.children.sort(key=lambda i: i.name)
+
+    # set metadata for the files generated by this script.
+    i = cls.ITEMS.get("system/recovery-from-boot.p", None)
+    if i: i.uid, i.gid, i.mode = 0, 0, 0644
+    i = cls.ITEMS.get("system/etc/install-recovery.sh", None)
+    if i: i.uid, i.gid, i.mode = 0, 0, 0544
+
+  def CountChildMetadata(self):
+    """Count up the (uid, gid, mode) tuples for all children and
+    determine the best strategy for using set_perm_recursive and
+    set_perm to correctly chown/chmod all the files to their desired
+    values.  Recursively calls itself for all descendants.
+
+    Returns a dict of {(uid, gid, dmode, fmode): count} counting up
+    all descendants of this node.  (dmode or fmode may be None.)  Also
+    sets the best_subtree of each directory Item to the (uid, gid,
+    dmode, fmode) tuple that will match the most descendants of that
+    Item.
+    """
+
+    assert self.dir
+    d = self.descendants = {(self.uid, self.gid, self.mode, None): 1}
+    for i in self.children:
+      if i.dir:
+        for k, v in i.CountChildMetadata().iteritems():
+          d[k] = d.get(k, 0) + v
+      else:
+        k = (i.uid, i.gid, None, i.mode)
+        d[k] = d.get(k, 0) + 1
+
+    # Find the (uid, gid, dmode, fmode) tuple that matches the most
+    # descendants.
+
+    # First, find the (uid, gid) pair that matches the most
+    # descendants.
+    ug = {}
+    for (uid, gid, _, _), count in d.iteritems():
+      ug[(uid, gid)] = ug.get((uid, gid), 0) + count
+    ug = MostPopularKey(ug, (0, 0))
+
+    # Now find the dmode and fmode that match the most descendants
+    # with that (uid, gid), and choose those.
+    best_dmode = (0, 0755)
+    best_fmode = (0, 0644)
+    for k, count in d.iteritems():
+      if k[:2] != ug: continue
+      if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2])
+      if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3])
+    self.best_subtree = ug + (best_dmode[1], best_fmode[1])
+
+    return d
+
+  def SetPermissions(self, script):
+    """Append set_perm/set_perm_recursive commands to 'script' to
+    set all permissions, users, and groups for the tree of files
+    rooted at 'self'."""
+
+    self.CountChildMetadata()
+
+    def recurse(item, current):
+      # current is the (uid, gid, dmode, fmode) tuple that the current
+      # item (and all its children) have already been set to.  We only
+      # need to issue set_perm/set_perm_recursive commands if we're
+      # supposed to be something different.
+      if item.dir:
+        if current != item.best_subtree:
+          script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
+          current = item.best_subtree
+
+        if item.uid != current[0] or item.gid != current[1] or \
+           item.mode != current[2]:
+          script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode)
+
+        for i in item.children:
+          recurse(i, current)
+      else:
+        if item.uid != current[0] or item.gid != current[1] or \
+               item.mode != current[3]:
+          script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode)
+
+    recurse(self, (-1, -1, -1, -1))
+
+
+def CopySystemFiles(input_zip, output_zip=None,
+                    substitute=None):
+  """Copies files underneath system/ in the input zip to the output
+  zip.  Populates the Item class with their metadata, and returns a
+  list of symlinks.  output_zip may be None, in which case the copy is
+  skipped (but the other side effects still happen).  substitute is an
+  optional dict of {output filename: contents} to be output instead of
+  certain input files.
+  """
+
+  symlinks = []
+
+  for info in input_zip.infolist():
+    if info.filename.startswith("SYSTEM/"):
+      basefilename = info.filename[7:]
+      if IsSymlink(info):
+        symlinks.append((input_zip.read(info.filename),
+                         "/system/" + basefilename))
+      else:
+        info2 = copy.copy(info)
+        fn = info2.filename = "system/" + basefilename
+        if substitute and fn in substitute and substitute[fn] is None:
+          continue
+        if output_zip is not None:
+          if substitute and fn in substitute:
+            data = substitute[fn]
+          else:
+            data = input_zip.read(info.filename)
+          output_zip.writestr(info2, data)
+        if fn.endswith("/"):
+          Item.Get(fn[:-1], dir=True)
+        else:
+          Item.Get(fn, dir=False)
+
+  symlinks.sort()
+  return symlinks
+
+
+def SignOutput(temp_zip_name, output_zip_name):
+  key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
+  pw = key_passwords[OPTIONS.package_key]
+
+  common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
+                  whole_file=True)
+
+
+def AppendAssertions(script, input_zip):
+  device = GetBuildProp("ro.product.device", input_zip)
+  script.AssertDevice(device)
+
+
+def MakeRecoveryPatch(output_zip, recovery_img, boot_img):
+  """Generate a binary patch that creates the recovery image starting
+  with the boot image.  (Most of the space in these images is just the
+  kernel, which is identical for the two, so the resulting patch
+  should be efficient.)  Add it to the output zip, along with a shell
+  script that is run from init.rc on first boot to actually do the
+  patching and install the new recovery image.
+
+  recovery_img and boot_img should be File objects for the
+  corresponding images.
+
+  Returns an Item for the shell script, which must be made
+  executable.
+  """
+
+  d = common.Difference(recovery_img, boot_img)
+  _, _, patch = d.ComputePatch()
+  common.ZipWriteStr(output_zip, "recovery/recovery-from-boot.p", patch)
+  Item.Get("system/recovery-from-boot.p", dir=False)
+
+  boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
+  recovery_type, recovery_device = common.GetTypeAndDevice("/recovery", OPTIONS.info_dict)
+
+  # Images with different content will have a different first page, so
+  # we check to see if this recovery has already been installed by
+  # testing just the first 2k.
+  HEADER_SIZE = 2048
+  header_sha1 = sha.sha(recovery_img.data[:HEADER_SIZE]).hexdigest()
+  sh = """#!/system/bin/sh
+if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(header_size)d:%(header_sha1)s; then
+  log -t recovery "Installing new recovery image"
+  applypatch %(boot_type)s:%(boot_device)s:%(boot_size)d:%(boot_sha1)s %(recovery_type)s:%(recovery_device)s %(recovery_sha1)s %(recovery_size)d %(boot_sha1)s:/system/recovery-from-boot.p
+else
+  log -t recovery "Recovery image already installed"
+fi
+""" % { 'boot_size': boot_img.size,
+        'boot_sha1': boot_img.sha1,
+        'header_size': HEADER_SIZE,
+        'header_sha1': header_sha1,
+        'recovery_size': recovery_img.size,
+        'recovery_sha1': recovery_img.sha1,
+        'boot_type': boot_type,
+        'boot_device': boot_device,
+        'recovery_type': recovery_type,
+        'recovery_device': recovery_device,
+        }
+  common.ZipWriteStr(output_zip, "recovery/etc/install-recovery.sh", sh)
+  return Item.Get("system/etc/install-recovery.sh", dir=False)
+
+
+def WriteFullOTAPackage(input_zip, output_zip):
+  # TODO: how to determine this?  We don't know what version it will
+  # be installed on top of.  For now, we expect the API just won't
+  # change very often.
+  script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
+
+  metadata = {"post-build": GetBuildProp("ro.build.fingerprint", input_zip),
+              "pre-device": GetBuildProp("ro.product.device", input_zip),
+              "post-timestamp": GetBuildProp("ro.build.date.utc", input_zip),
+              }
+
+  device_specific = common.DeviceSpecificParams(
+      input_zip=input_zip,
+      input_version=OPTIONS.info_dict["recovery_api_version"],
+      output_zip=output_zip,
+      script=script,
+      input_tmp=OPTIONS.input_tmp,
+      metadata=metadata,
+      info_dict=OPTIONS.info_dict)
+
+  if not OPTIONS.omit_prereq:
+    ts = GetBuildProp("ro.build.date.utc", input_zip)
+    script.AssertOlderBuild(ts)
+
+  AppendAssertions(script, input_zip)
+  device_specific.FullOTA_Assertions()
+
+  script.ShowProgress(0.5, 0)
+
+  if OPTIONS.wipe_user_data:
+    script.FormatPartition("/data")
+
+  script.FormatPartition("/system")
+  script.Mount("/system")
+  script.UnpackPackageDir("recovery", "/system")
+  script.UnpackPackageDir("system", "/system")
+
+  symlinks = CopySystemFiles(input_zip, output_zip)
+  script.MakeSymlinks(symlinks)
+
+  boot_img = common.File("boot.img", common.BuildBootableImage(
+      os.path.join(OPTIONS.input_tmp, "BOOT")))
+  recovery_img = common.File("recovery.img", common.BuildBootableImage(
+      os.path.join(OPTIONS.input_tmp, "RECOVERY")))
+  MakeRecoveryPatch(output_zip, recovery_img, boot_img)
+
+  Item.GetMetadata(input_zip)
+  Item.Get("system").SetPermissions(script)
+
+  common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
+  common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
+  script.ShowProgress(0.2, 0)
+
+  script.ShowProgress(0.2, 10)
+  script.WriteRawImage("/boot", "boot.img")
+
+  script.ShowProgress(0.1, 0)
+  device_specific.FullOTA_InstallEnd()
+
+  if OPTIONS.extra_script is not None:
+    script.AppendExtra(OPTIONS.extra_script)
+
+  script.UnmountAll()
+  script.AddToZip(input_zip, output_zip)
+  WriteMetadata(metadata, output_zip)
+
+
+def WriteMetadata(metadata, output_zip):
+  common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
+                     "".join(["%s=%s\n" % kv
+                              for kv in sorted(metadata.iteritems())]))
+
+
+
+
+def LoadSystemFiles(z):
+  """Load all the files from SYSTEM/... in a given target-files
+  ZipFile, and return a dict of {filename: File object}."""
+  out = {}
+  for info in z.infolist():
+    if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
+      fn = "system/" + info.filename[7:]
+      data = z.read(info.filename)
+      out[fn] = common.File(fn, data)
+  return out
+
+
+def GetBuildProp(property, z):
+  """Return the fingerprint of the build of a given target-files
+  ZipFile object."""
+  bp = z.read("SYSTEM/build.prop")
+  if not property:
+    return bp
+  m = re.search(re.escape(property) + r"=(.*)\n", bp)
+  if not m:
+    raise common.ExternalError("couldn't find %s in build.prop" % (property,))
+  return m.group(1).strip()
+
+
+def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
+  source_version = OPTIONS.source_info_dict["recovery_api_version"]
+  target_version = OPTIONS.target_info_dict["recovery_api_version"]
+
+  if source_version == 0:
+    print ("WARNING: generating edify script for a source that "
+           "can't install it.")
+  script = edify_generator.EdifyGenerator(source_version, OPTIONS.info_dict)
+
+  metadata = {"pre-device": GetBuildProp("ro.product.device", source_zip),
+              "post-timestamp": GetBuildProp("ro.build.date.utc", target_zip),
+              }
+
+  device_specific = common.DeviceSpecificParams(
+      source_zip=source_zip,
+      source_version=source_version,
+      target_zip=target_zip,
+      target_version=target_version,
+      output_zip=output_zip,
+      script=script,
+      metadata=metadata,
+      info_dict=OPTIONS.info_dict)
+
+  print "Loading target..."
+  target_data = LoadSystemFiles(target_zip)
+  print "Loading source..."
+  source_data = LoadSystemFiles(source_zip)
+
+  verbatim_targets = []
+  patch_list = []
+  diffs = []
+  largest_source_size = 0
+  for fn in sorted(target_data.keys()):
+    tf = target_data[fn]
+    assert fn == tf.name
+    sf = source_data.get(fn, None)
+
+    if sf is None or fn in OPTIONS.require_verbatim:
+      # This file should be included verbatim
+      if fn in OPTIONS.prohibit_verbatim:
+        raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
+      print "send", fn, "verbatim"
+      tf.AddToZip(output_zip)
+      verbatim_targets.append((fn, tf.size))
+    elif tf.sha1 != sf.sha1:
+      # File is different; consider sending as a patch
+      diffs.append(common.Difference(tf, sf))
+    else:
+      # Target file identical to source.
+      pass
+
+  common.ComputeDifferences(diffs)
+
+  for diff in diffs:
+    tf, sf, d = diff.GetPatch()
+    if d is None or len(d) > tf.size * OPTIONS.patch_threshold:
+      # patch is almost as big as the file; don't bother patching
+      tf.AddToZip(output_zip)
+      verbatim_targets.append((tf.name, tf.size))
+    else:
+      common.ZipWriteStr(output_zip, "patch/" + tf.name + ".p", d)
+      patch_list.append((tf.name, tf, sf, tf.size, sha.sha(d).hexdigest()))
+      largest_source_size = max(largest_source_size, sf.size)
+
+  source_fp = GetBuildProp("ro.build.fingerprint", source_zip)
+  target_fp = GetBuildProp("ro.build.fingerprint", target_zip)
+  metadata["pre-build"] = source_fp
+  metadata["post-build"] = target_fp
+
+  script.Mount("/system")
+  script.AssertSomeFingerprint(source_fp, target_fp)
+
+  source_boot = common.File("/tmp/boot.img",
+                            common.BuildBootableImage(
+                                os.path.join(OPTIONS.source_tmp, "BOOT")))
+  target_boot = common.File("/tmp/boot.img",
+                            common.BuildBootableImage(
+                                os.path.join(OPTIONS.target_tmp, "BOOT")))
+  updating_boot = (source_boot.data != target_boot.data)
+
+  source_recovery = common.File("system/recovery.img",
+                                common.BuildBootableImage(
+                                    os.path.join(OPTIONS.source_tmp, "RECOVERY")))
+  target_recovery = common.File("system/recovery.img",
+                                common.BuildBootableImage(
+                                    os.path.join(OPTIONS.target_tmp, "RECOVERY")))
+  updating_recovery = (source_recovery.data != target_recovery.data)
+
+  # Here's how we divide up the progress bar:
+  #  0.1 for verifying the start state (PatchCheck calls)
+  #  0.8 for applying patches (ApplyPatch calls)
+  #  0.1 for unpacking verbatim files, symlinking, and doing the
+  #      device-specific commands.
+
+  AppendAssertions(script, target_zip)
+  device_specific.IncrementalOTA_Assertions()
+
+  script.Print("Verifying current system...")
+
+  script.ShowProgress(0.1, 0)
+  total_verify_size = float(sum([i[2].size for i in patch_list]) + 1)
+  if updating_boot:
+    total_verify_size += source_boot.size
+  so_far = 0
+
+  for fn, tf, sf, size, patch_sha in patch_list:
+    script.PatchCheck("/"+fn, tf.sha1, sf.sha1)
+    so_far += sf.size
+    script.SetProgress(so_far / total_verify_size)
+
+  if updating_boot:
+    d = common.Difference(target_boot, source_boot)
+    _, _, d = d.ComputePatch()
+    print "boot      target: %d  source: %d  diff: %d" % (
+        target_boot.size, source_boot.size, len(d))
+
+    common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
+
+    boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
+
+    script.PatchCheck("%s:%s:%d:%s:%d:%s" %
+                      (boot_type, boot_device,
+                       source_boot.size, source_boot.sha1,
+                       target_boot.size, target_boot.sha1))
+    so_far += source_boot.size
+    script.SetProgress(so_far / total_verify_size)
+
+  if patch_list or updating_recovery or updating_boot:
+    script.CacheFreeSpaceCheck(largest_source_size)
+
+  device_specific.IncrementalOTA_VerifyEnd()
+
+  script.Comment("---- start making changes here ----")
+
+  if OPTIONS.wipe_user_data:
+    script.Print("Erasing user data...")
+    script.FormatPartition("/data")
+
+  script.Print("Removing unneeded files...")
+  script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
+                     ["/"+i for i in sorted(source_data)
+                            if i not in target_data] +
+                     ["/system/recovery.img"])
+
+  script.ShowProgress(0.8, 0)
+  total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
+  if updating_boot:
+    total_patch_size += target_boot.size
+  so_far = 0
+
+  script.Print("Patching system files...")
+  for fn, tf, sf, size, _ in patch_list:
+    script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
+    so_far += tf.size
+    script.SetProgress(so_far / total_patch_size)
+
+  if updating_boot:
+    # Produce the boot image by applying a patch to the current
+    # contents of the boot partition, and write it back to the
+    # partition.
+    script.Print("Patching boot image...")
+    script.ApplyPatch("%s:%s:%d:%s:%d:%s"
+                      % (boot_type, boot_device,
+                         source_boot.size, source_boot.sha1,
+                         target_boot.size, target_boot.sha1),
+                      "-",
+                      target_boot.size, target_boot.sha1,
+                      source_boot.sha1, "patch/boot.img.p")
+    so_far += target_boot.size
+    script.SetProgress(so_far / total_patch_size)
+    print "boot image changed; including."
+  else:
+    print "boot image unchanged; skipping."
+
+  if updating_recovery:
+    # Is it better to generate recovery as a patch from the current
+    # boot image, or from the previous recovery image?  For large
+    # updates with significant kernel changes, probably the former.
+    # For small updates where the kernel hasn't changed, almost
+    # certainly the latter.  We pick the first option.  Future
+    # complicated schemes may let us effectively use both.
+    #
+    # A wacky possibility: as long as there is room in the boot
+    # partition, include the binaries and image files from recovery in
+    # the boot image (though not in the ramdisk) so they can be used
+    # as fodder for constructing the recovery image.
+    MakeRecoveryPatch(output_zip, target_recovery, target_boot)
+    script.DeleteFiles(["/system/recovery-from-boot.p",
+                        "/system/etc/install-recovery.sh"])
+    print "recovery image changed; including as patch from boot."
+  else:
+    print "recovery image unchanged; skipping."
+
+  script.ShowProgress(0.1, 10)
+
+  target_symlinks = CopySystemFiles(target_zip, None)
+
+  target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
+  temp_script = script.MakeTemporary()
+  Item.GetMetadata(target_zip)
+  Item.Get("system").SetPermissions(temp_script)
+
+  # Note that this call will mess up the tree of Items, so make sure
+  # we're done with it.
+  source_symlinks = CopySystemFiles(source_zip, None)
+  source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
+
+  # Delete all the symlinks in source that aren't in target.  This
+  # needs to happen before verbatim files are unpacked, in case a
+  # symlink in the source is replaced by a real file in the target.
+  to_delete = []
+  for dest, link in source_symlinks:
+    if link not in target_symlinks_d:
+      to_delete.append(link)
+  script.DeleteFiles(to_delete)
+
+  if verbatim_targets:
+    script.Print("Unpacking new files...")
+    script.UnpackPackageDir("system", "/system")
+
+  if updating_recovery:
+    script.Print("Unpacking new recovery...")
+    script.UnpackPackageDir("recovery", "/system")
+
+  script.Print("Symlinks and permissions...")
+
+  # Create all the symlinks that don't already exist, or point to
+  # somewhere different than what we want.  Delete each symlink before
+  # creating it, since the 'symlink' command won't overwrite.
+  to_create = []
+  for dest, link in target_symlinks:
+    if link in source_symlinks_d:
+      if dest != source_symlinks_d[link]:
+        to_create.append((dest, link))
+    else:
+      to_create.append((dest, link))
+  script.DeleteFiles([i[1] for i in to_create])
+  script.MakeSymlinks(to_create)
+
+  # Now that the symlinks are created, we can set all the
+  # permissions.
+  script.AppendScript(temp_script)
+
+  # Do device-specific installation (eg, write radio image).
+  device_specific.IncrementalOTA_InstallEnd()
+
+  if OPTIONS.extra_script is not None:
+    scirpt.AppendExtra(OPTIONS.extra_script)
+
+  script.AddToZip(target_zip, output_zip)
+  WriteMetadata(metadata, output_zip)
+
+
+def main(argv):
+
+  def option_handler(o, a):
+    if o in ("-b", "--board_config"):
+      pass   # deprecated
+    elif o in ("-k", "--package_key"):
+      OPTIONS.package_key = a
+    elif o in ("-i", "--incremental_from"):
+      OPTIONS.incremental_source = a
+    elif o in ("-w", "--wipe_user_data"):
+      OPTIONS.wipe_user_data = True
+    elif o in ("-n", "--no_prereq"):
+      OPTIONS.omit_prereq = True
+    elif o in ("-e", "--extra_script"):
+      OPTIONS.extra_script = a
+    elif o in ("--worker_threads"):
+      OPTIONS.worker_threads = int(a)
+    else:
+      return False
+    return True
+
+  args = common.ParseOptions(argv, __doc__,
+                             extra_opts="b:k:i:d:wne:",
+                             extra_long_opts=["board_config=",
+                                              "package_key=",
+                                              "incremental_from=",
+                                              "wipe_user_data",
+                                              "no_prereq",
+                                              "extra_script=",
+                                              "worker_threads="],
+                             extra_option_handler=option_handler)
+
+  if len(args) != 2:
+    common.Usage(__doc__)
+    sys.exit(1)
+
+  if OPTIONS.extra_script is not None:
+    OPTIONS.extra_script = open(OPTIONS.extra_script).read()
+
+  print "unzipping target target-files..."
+  OPTIONS.input_tmp = common.UnzipTemp(args[0])
+
+  OPTIONS.target_tmp = OPTIONS.input_tmp
+  input_zip = zipfile.ZipFile(args[0], "r")
+  OPTIONS.info_dict = common.LoadInfoDict(input_zip)
+  if OPTIONS.verbose:
+    print "--- target info ---"
+    common.DumpInfoDict(OPTIONS.info_dict)
+
+  if OPTIONS.device_specific is None:
+    OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
+  if OPTIONS.device_specific is not None:
+    OPTIONS.device_specific = os.path.normpath(OPTIONS.device_specific)
+    print "using device-specific extensions in", OPTIONS.device_specific
+
+  if OPTIONS.package_key:
+    temp_zip_file = tempfile.NamedTemporaryFile()
+    output_zip = zipfile.ZipFile(temp_zip_file, "w",
+                                 compression=zipfile.ZIP_DEFLATED)
+  else:
+    output_zip = zipfile.ZipFile(args[1], "w",
+                                 compression=zipfile.ZIP_DEFLATED)
+
+  if OPTIONS.incremental_source is None:
+    WriteFullOTAPackage(input_zip, output_zip)
+  else:
+    print "unzipping source target-files..."
+    OPTIONS.source_tmp = common.UnzipTemp(OPTIONS.incremental_source)
+    source_zip = zipfile.ZipFile(OPTIONS.incremental_source, "r")
+    OPTIONS.target_info_dict = OPTIONS.info_dict
+    OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
+    if OPTIONS.verbose:
+      print "--- source info ---"
+      common.DumpInfoDict(OPTIONS.source_info_dict)
+    WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
+
+  output_zip.close()
+  if OPTIONS.package_key:
+    SignOutput(temp_zip_file.name, args[1])
+    temp_zip_file.close()
+
+  common.Cleanup()
+
+  print "done."
+
+
+if __name__ == '__main__':
+  try:
+    main(sys.argv[1:])
+  except common.ExternalError, e:
+    print
+    print "   ERROR: %s" % (e,)
+    print
+    sys.exit(1)
diff --git a/build/tools/releasetools/sign_target_files_apks b/build/tools/releasetools/sign_target_files_apks
new file mode 100644 (file)
index 0000000..5fca691
--- /dev/null
@@ -0,0 +1,317 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Signs all the APK files in a target-files zipfile, producing a new
+target-files zip.
+
+Usage:  sign_target_files_apks [flags] input_target_files output_target_files
+
+  -e  (--extra_apks)  <name,name,...=key>
+      Add extra APK name/key pairs as though they appeared in
+      apkcerts.txt (so mappings specified by -k and -d are applied).
+      Keys specified in -e override any value for that app contained
+      in the apkcerts.txt file.  Option may be repeated to give
+      multiple extra packages.
+
+  -k  (--key_mapping)  <src_key=dest_key>
+      Add a mapping from the key name as specified in apkcerts.txt (the
+      src_key) to the real key you wish to sign the package with
+      (dest_key).  Option may be repeated to give multiple key
+      mappings.
+
+  -d  (--default_key_mappings)  <dir>
+      Set up the following key mappings:
+
+        build/target/product/security/testkey   ==>  $dir/releasekey
+        build/target/product/security/media     ==>  $dir/media
+        build/target/product/security/shared    ==>  $dir/shared
+        build/target/product/security/platform  ==>  $dir/platform
+
+      -d and -k options are added to the set of mappings in the order
+      in which they appear on the command line.
+
+  -o  (--replace_ota_keys)
+      Replace the certificate (public key) used by OTA package
+      verification with the one specified in the input target_files
+      zip (in the META/otakeys.txt file).  Key remapping (-k and -d)
+      is performed on this key.
+
+  -t  (--tag_changes)  <+tag>,<-tag>,...
+      Comma-separated list of changes to make to the set of tags (in
+      the last component of the build fingerprint).  Prefix each with
+      '+' or '-' to indicate whether that tag should be added or
+      removed.  Changes are processed in the order they appear.
+      Default value is "-test-keys,+release-keys".
+
+"""
+
+import sys
+
+if sys.hexversion < 0x02040000:
+  print >> sys.stderr, "Python 2.4 or newer is required."
+  sys.exit(1)
+
+import cStringIO
+import copy
+import os
+import re
+import subprocess
+import tempfile
+import zipfile
+
+import common
+
+OPTIONS = common.OPTIONS
+
+OPTIONS.extra_apks = {}
+OPTIONS.key_map = {}
+OPTIONS.replace_ota_keys = False
+OPTIONS.tag_changes = ("-test-keys", "+release-keys")
+
+def GetApkCerts(tf_zip):
+  certmap = common.ReadApkCerts(tf_zip)
+
+  # apply the key remapping to the contents of the file
+  for apk, cert in certmap.iteritems():
+    certmap[apk] = OPTIONS.key_map.get(cert, cert)
+
+  # apply all the -e options, overriding anything in the file
+  for apk, cert in OPTIONS.extra_apks.iteritems():
+    if not cert:
+      cert = "PRESIGNED"
+    certmap[apk] = OPTIONS.key_map.get(cert, cert)
+
+  return certmap
+
+
+def CheckAllApksSigned(input_tf_zip, apk_key_map):
+  """Check that all the APKs we want to sign have keys specified, and
+  error out if they don't."""
+  unknown_apks = []
+  for info in input_tf_zip.infolist():
+    if info.filename.endswith(".apk"):
+      name = os.path.basename(info.filename)
+      if name not in apk_key_map:
+        unknown_apks.append(name)
+  if unknown_apks:
+    print "ERROR: no key specified for:\n\n ",
+    print "\n  ".join(unknown_apks)
+    print "\nUse '-e <apkname>=' to specify a key (which may be an"
+    print "empty string to not sign this apk)."
+    sys.exit(1)
+
+
+def SignApk(data, keyname, pw):
+  unsigned = tempfile.NamedTemporaryFile()
+  unsigned.write(data)
+  unsigned.flush()
+
+  signed = tempfile.NamedTemporaryFile()
+
+  common.SignFile(unsigned.name, signed.name, keyname, pw, align=4)
+
+  data = signed.read()
+  unsigned.close()
+  signed.close()
+
+  return data
+
+
+def SignApks(input_tf_zip, output_tf_zip, apk_key_map, key_passwords):
+  maxsize = max([len(os.path.basename(i.filename))
+                 for i in input_tf_zip.infolist()
+                 if i.filename.endswith('.apk')])
+
+  for info in input_tf_zip.infolist():
+    data = input_tf_zip.read(info.filename)
+    out_info = copy.copy(info)
+    if info.filename.endswith(".apk"):
+      name = os.path.basename(info.filename)
+      key = apk_key_map[name]
+      if key not in common.SPECIAL_CERT_STRINGS:
+        print "    signing: %-*s (%s)" % (maxsize, name, key)
+        signed_data = SignApk(data, key, key_passwords[key])
+        output_tf_zip.writestr(out_info, signed_data)
+      else:
+        # an APK we're not supposed to sign.
+        print "NOT signing: %s" % (name,)
+        output_tf_zip.writestr(out_info, data)
+    elif info.filename in ("SYSTEM/build.prop",
+                           "RECOVERY/RAMDISK/default.prop"):
+      print "rewriting %s:" % (info.filename,)
+      new_data = RewriteProps(data)
+      output_tf_zip.writestr(out_info, new_data)
+    else:
+      # a non-APK file; copy it verbatim
+      output_tf_zip.writestr(out_info, data)
+
+
+def EditTags(tags):
+  """Given a string containing comma-separated tags, apply the edits
+  specified in OPTIONS.tag_changes and return the updated string."""
+  tags = set(tags.split(","))
+  for ch in OPTIONS.tag_changes:
+    if ch[0] == "-":
+      tags.discard(ch[1:])
+    elif ch[0] == "+":
+      tags.add(ch[1:])
+  return ",".join(sorted(tags))
+
+
+def RewriteProps(data):
+  output = []
+  for line in data.split("\n"):
+    line = line.strip()
+    original_line = line
+    if line and line[0] != '#':
+      key, value = line.split("=", 1)
+      if key == "ro.build.fingerprint":
+        pieces = value.split("/")
+        pieces[-1] = EditTags(pieces[-1])
+        value = "/".join(pieces)
+      elif key == "ro.build.description":
+        pieces = value.split(" ")
+        assert len(pieces) == 5
+        pieces[-1] = EditTags(pieces[-1])
+        value = " ".join(pieces)
+      elif key == "ro.build.tags":
+        value = EditTags(value)
+      line = key + "=" + value
+    if line != original_line:
+      print "  replace: ", original_line
+      print "     with: ", line
+    output.append(line)
+  return "\n".join(output) + "\n"
+
+
+def ReplaceOtaKeys(input_tf_zip, output_tf_zip):
+  try:
+    keylist = input_tf_zip.read("META/otakeys.txt").split()
+  except KeyError:
+    raise ExternalError("can't read META/otakeys.txt from input")
+
+  mapped_keys = []
+  for k in keylist:
+    m = re.match(r"^(.*)\.x509\.pem$", k)
+    if not m:
+      raise ExternalError("can't parse \"%s\" from META/otakeys.txt" % (k,))
+    k = m.group(1)
+    mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
+
+  if mapped_keys:
+    print "using:\n   ", "\n   ".join(mapped_keys)
+    print "for OTA package verification"
+  else:
+    mapped_keys.append(
+        OPTIONS.key_map["build/target/product/security/testkey"] + ".x509.pem")
+    print "META/otakeys.txt has no keys; using", mapped_keys[0]
+
+  # recovery uses a version of the key that has been slightly
+  # predigested (by DumpPublicKey.java) and put in res/keys.
+
+  p = common.Run(["java", "-jar",
+                  os.path.join(OPTIONS.search_path, "framework", "dumpkey.jar")]
+                 + mapped_keys,
+                 stdout=subprocess.PIPE)
+  data, _ = p.communicate()
+  if p.returncode != 0:
+    raise ExternalError("failed to run dumpkeys")
+  common.ZipWriteStr(output_tf_zip, "RECOVERY/RAMDISK/res/keys", data)
+
+  # SystemUpdateActivity uses the x509.pem version of the keys, but
+  # put into a zipfile system/etc/security/otacerts.zip.
+
+  tempfile = cStringIO.StringIO()
+  certs_zip = zipfile.ZipFile(tempfile, "w")
+  for k in mapped_keys:
+    certs_zip.write(k)
+  certs_zip.close()
+  common.ZipWriteStr(output_tf_zip, "SYSTEM/etc/security/otacerts.zip",
+                     tempfile.getvalue())
+
+
+def main(argv):
+
+  def option_handler(o, a):
+    if o in ("-e", "--extra_apks"):
+      names, key = a.split("=")
+      names = names.split(",")
+      for n in names:
+        OPTIONS.extra_apks[n] = key
+    elif o in ("-d", "--default_key_mappings"):
+      OPTIONS.key_map.update({
+          "build/target/product/security/testkey": "%s/releasekey" % (a,),
+          "build/target/product/security/media": "%s/media" % (a,),
+          "build/target/product/security/shared": "%s/shared" % (a,),
+          "build/target/product/security/platform": "%s/platform" % (a,),
+          })
+    elif o in ("-k", "--key_mapping"):
+      s, d = a.split("=")
+      OPTIONS.key_map[s] = d
+    elif o in ("-o", "--replace_ota_keys"):
+      OPTIONS.replace_ota_keys = True
+    elif o in ("-t", "--tag_changes"):
+      new = []
+      for i in a.split(","):
+        i = i.strip()
+        if not i or i[0] not in "-+":
+          raise ValueError("Bad tag change '%s'" % (i,))
+        new.append(i[0] + i[1:].strip())
+      OPTIONS.tag_changes = tuple(new)
+    else:
+      return False
+    return True
+
+  args = common.ParseOptions(argv, __doc__,
+                             extra_opts="e:d:k:ot:",
+                             extra_long_opts=["extra_apks=",
+                                              "default_key_mappings=",
+                                              "key_mapping=",
+                                              "replace_ota_keys",
+                                              "tag_changes="],
+                             extra_option_handler=option_handler)
+
+  if len(args) != 2:
+    common.Usage(__doc__)
+    sys.exit(1)
+
+  input_zip = zipfile.ZipFile(args[0], "r")
+  output_zip = zipfile.ZipFile(args[1], "w")
+
+  apk_key_map = GetApkCerts(input_zip)
+  CheckAllApksSigned(input_zip, apk_key_map)
+
+  key_passwords = common.GetKeyPasswords(set(apk_key_map.values()))
+  SignApks(input_zip, output_zip, apk_key_map, key_passwords)
+
+  if OPTIONS.replace_ota_keys:
+    ReplaceOtaKeys(input_zip, output_zip)
+
+  input_zip.close()
+  output_zip.close()
+
+  print "done."
+
+
+if __name__ == '__main__':
+  try:
+    main(sys.argv[1:])
+  except common.ExternalError, e:
+    print
+    print "   ERROR: %s" % (e,)
+    print
+    sys.exit(1)
diff --git a/build/tools/rgb2565/Android.mk b/build/tools/rgb2565/Android.mk
new file mode 100644 (file)
index 0000000..189584d
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright 2008 The Android Open Source Project
+#
+# Android.mk for rgb2565
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+# rgb2565 host tool
+# =========================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := to565.c
+
+LOCAL_CFLAGS += -O2 -Wall -Wno-unused-parameter
+LOCAL_MODULE := rgb2565
+
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/build/tools/rgb2565/to565.c b/build/tools/rgb2565/to565.c
new file mode 100644 (file)
index 0000000..abf9cdb
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+       
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#define to565(r,g,b)                                            \
+    ((((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3))
+
+#define from565_r(x) ((((x) >> 11) & 0x1f) * 255 / 31)
+#define from565_g(x) ((((x) >> 5) & 0x3f) * 255 / 63)
+#define from565_b(x) (((x) & 0x1f) * 255 / 31)
+
+void to_565_raw(void)
+{
+    unsigned char in[3];
+    unsigned short out;
+
+    while(read(0, in, 3) == 3) {
+        out = to565(in[0],in[1],in[2]);
+        write(1, &out, 2);
+    }
+    return;
+}
+
+void to_565_raw_dither(int width)
+{
+    unsigned char in[3];
+    unsigned short out;
+    int i = 0;
+    int e;
+
+    int* error = malloc((width+2) * 3 * sizeof(int));
+    int* next_error = malloc((width+2) * 3 * sizeof(int));
+    memset(error, 0, (width+2) * 3 * sizeof(int));
+    memset(next_error, 0, (width+2) * 3 * sizeof(int));
+    error += 3;        // array goes from [-3..((width+1)*3+2)]
+    next_error += 3;
+
+    while(read(0, in, 3) == 3) {
+        int r = in[0] + error[i*3+0];
+        int rb = (r < 0) ? 0 : ((r > 255) ? 255 : r);
+
+        int g = in[1] + error[i*3+1];
+        int gb = (g < 0) ? 0 : ((g > 255) ? 255 : g);
+
+        int b = in[2] + error[i*3+2];
+        int bb = (b < 0) ? 0 : ((b > 255) ? 255 : b);
+
+        out = to565(rb, gb, bb);
+        write(1, &out, 2);
+
+#define apply_error(ch) {                                               \
+            next_error[(i-1)*3+ch] += e * 3 / 16;                       \
+            next_error[(i)*3+ch] += e * 5 / 16;                         \
+            next_error[(i+1)*3+ch] += e * 1 / 16;                       \
+            error[(i+1)*3+ch] += e - ((e*1/16) + (e*3/16) + (e*5/16));  \
+        }
+
+        e = r - from565_r(out);
+        apply_error(0);
+
+        e = g - from565_g(out);
+        apply_error(1);
+
+        e = b - from565_b(out);
+        apply_error(2);
+
+#undef apply_error
+
+        ++i;
+        if (i == width) {
+            // error <- next_error; next_error <- 0
+            int* temp = error; error = next_error; next_error = temp;
+            memset(next_error, 0, (width+1) * 3 * sizeof(int));
+            i = 0;
+        }
+    }
+
+    free(error-3);
+    free(next_error-3);
+
+    return;
+}
+
+void to_565_rle(void)
+{
+    unsigned char in[3];
+    unsigned short last, color, count;
+    unsigned total = 0;
+    count = 0;
+
+    while(read(0, in, 3) == 3) {
+        color = to565(in[0],in[1],in[2]);
+        if (count) {
+            if ((color == last) && (count != 65535)) {
+                count++;
+                continue;
+            } else {
+                write(1, &count, 2);
+                write(1, &last, 2);
+                total += count;
+            }
+        }
+        last = color;
+        count = 1;
+    }
+    if (count) {
+        write(1, &count, 2);
+        write(1, &last, 2);
+        total += count;
+    }
+    fprintf(stderr,"%d pixels\n",total);
+}
+
+int main(int argc, char **argv)
+{
+    if ((argc == 2) && (!strcmp(argv[1],"-rle"))) {
+        to_565_rle();
+    } else {
+        if (argc > 2 && (!strcmp(argv[1], "-w"))) {
+            to_565_raw_dither(atoi(argv[2]));
+        } else {
+            to_565_raw();
+        }
+    }
+    return 0;
+}
diff --git a/build/tools/signapk/Android.mk b/build/tools/signapk/Android.mk
new file mode 100644 (file)
index 0000000..b2de21c
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)
+
+# the signapk tool (a .jar application used to sign packages)
+# ============================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := signapk
+LOCAL_SRC_FILES := SignApk.java
+LOCAL_JAR_MANIFEST := SignApk.mf
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+ifeq ($(TARGET_BUILD_APPS),)
+# The post-build signing tools need signapk.jar, but we don't
+# need this if we're just doing unbundled apps.
+$(call dist-for-goals,droidcore,$(LOCAL_INSTALLED_MODULE))
+endif
diff --git a/build/tools/signapk/SignApk.java b/build/tools/signapk/SignApk.java
new file mode 100644 (file)
index 0000000..c4d73c8
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.signapk;
+
+import sun.misc.BASE64Encoder;
+import sun.security.pkcs.ContentInfo;
+import sun.security.pkcs.PKCS7;
+import sun.security.pkcs.SignerInfo;
+import sun.security.x509.AlgorithmId;
+import sun.security.x509.X500Name;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.security.AlgorithmParameters;
+import java.security.DigestOutputStream;
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.MessageDigest;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.regex.Pattern;
+import javax.crypto.Cipher;
+import javax.crypto.EncryptedPrivateKeyInfo;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+
+/**
+ * Command line tool to sign JAR files (including APKs and OTA updates) in
+ * a way compatible with the mincrypt verifier, using SHA1 and RSA keys.
+ */
+class SignApk {
+    private static final String CERT_SF_NAME = "META-INF/CERT.SF";
+    private static final String CERT_RSA_NAME = "META-INF/CERT.RSA";
+
+    // Files matching this pattern are not copied to the output.
+    private static Pattern stripPattern =
+            Pattern.compile("^META-INF/(.*)[.](SF|RSA|DSA)$");
+
+    private static X509Certificate readPublicKey(File file)
+            throws IOException, GeneralSecurityException {
+        FileInputStream input = new FileInputStream(file);
+        try {
+            CertificateFactory cf = CertificateFactory.getInstance("X.509");
+            return (X509Certificate) cf.generateCertificate(input);
+        } finally {
+            input.close();
+        }
+    }
+
+    /**
+     * Reads the password from stdin and returns it as a string.
+     *
+     * @param keyFile The file containing the private key.  Used to prompt the user.
+     */
+    private static String readPassword(File keyFile) {
+        // TODO: use Console.readPassword() when it's available.
+        System.out.print("Enter password for " + keyFile + " (password will not be hidden): ");
+        System.out.flush();
+        BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
+        try {
+            return stdin.readLine();
+        } catch (IOException ex) {
+            return null;
+        }
+    }
+
+    /**
+     * Decrypt an encrypted PKCS 8 format private key.
+     *
+     * Based on ghstark's post on Aug 6, 2006 at
+     * http://forums.sun.com/thread.jspa?threadID=758133&messageID=4330949
+     *
+     * @param encryptedPrivateKey The raw data of the private key
+     * @param keyFile The file containing the private key
+     */
+    private static KeySpec decryptPrivateKey(byte[] encryptedPrivateKey, File keyFile)
+            throws GeneralSecurityException {
+        EncryptedPrivateKeyInfo epkInfo;
+        try {
+            epkInfo = new EncryptedPrivateKeyInfo(encryptedPrivateKey);
+        } catch (IOException ex) {
+            // Probably not an encrypted key.
+            return null;
+        }
+
+        char[] password = readPassword(keyFile).toCharArray();
+
+        SecretKeyFactory skFactory = SecretKeyFactory.getInstance(epkInfo.getAlgName());
+        Key key = skFactory.generateSecret(new PBEKeySpec(password));
+
+        Cipher cipher = Cipher.getInstance(epkInfo.getAlgName());
+        cipher.init(Cipher.DECRYPT_MODE, key, epkInfo.getAlgParameters());
+
+        try {
+            return epkInfo.getKeySpec(cipher);
+        } catch (InvalidKeySpecException ex) {
+            System.err.println("signapk: Password for " + keyFile + " may be bad.");
+            throw ex;
+        }
+    }
+
+    /** Read a PKCS 8 format private key. */
+    private static PrivateKey readPrivateKey(File file)
+            throws IOException, GeneralSecurityException {
+        DataInputStream input = new DataInputStream(new FileInputStream(file));
+        try {
+            byte[] bytes = new byte[(int) file.length()];
+            input.read(bytes);
+
+            KeySpec spec = decryptPrivateKey(bytes, file);
+            if (spec == null) {
+                spec = new PKCS8EncodedKeySpec(bytes);
+            }
+
+            try {
+                return KeyFactory.getInstance("RSA").generatePrivate(spec);
+            } catch (InvalidKeySpecException ex) {
+                return KeyFactory.getInstance("DSA").generatePrivate(spec);
+            }
+        } finally {
+            input.close();
+        }
+    }
+
+    /** Add the SHA1 of every file to the manifest, creating it if necessary. */
+    private static Manifest addDigestsToManifest(JarFile jar)
+            throws IOException, GeneralSecurityException {
+        Manifest input = jar.getManifest();
+        Manifest output = new Manifest();
+        Attributes main = output.getMainAttributes();
+        if (input != null) {
+            main.putAll(input.getMainAttributes());
+        } else {
+            main.putValue("Manifest-Version", "1.0");
+            main.putValue("Created-By", "1.0 (Android SignApk)");
+        }
+
+        BASE64Encoder base64 = new BASE64Encoder();
+        MessageDigest md = MessageDigest.getInstance("SHA1");
+        byte[] buffer = new byte[4096];
+        int num;
+
+        // We sort the input entries by name, and add them to the
+        // output manifest in sorted order.  We expect that the output
+        // map will be deterministic.
+
+        TreeMap<String, JarEntry> byName = new TreeMap<String, JarEntry>();
+
+        for (Enumeration<JarEntry> e = jar.entries(); e.hasMoreElements(); ) {
+            JarEntry entry = e.nextElement();
+            byName.put(entry.getName(), entry);
+        }
+
+        for (JarEntry entry: byName.values()) {
+            String name = entry.getName();
+            if (!entry.isDirectory() && !name.equals(JarFile.MANIFEST_NAME) &&
+                !name.equals(CERT_SF_NAME) && !name.equals(CERT_RSA_NAME) &&
+                (stripPattern == null ||
+                 !stripPattern.matcher(name).matches())) {
+                InputStream data = jar.getInputStream(entry);
+                while ((num = data.read(buffer)) > 0) {
+                    md.update(buffer, 0, num);
+                }
+
+                Attributes attr = null;
+                if (input != null) attr = input.getAttributes(name);
+                attr = attr != null ? new Attributes(attr) : new Attributes();
+                attr.putValue("SHA1-Digest", base64.encode(md.digest()));
+                output.getEntries().put(name, attr);
+            }
+        }
+
+        return output;
+    }
+
+    /** Write to another stream and also feed it to the Signature object. */
+    private static class SignatureOutputStream extends FilterOutputStream {
+        private Signature mSignature;
+        private int mCount;
+
+        public SignatureOutputStream(OutputStream out, Signature sig) {
+            super(out);
+            mSignature = sig;
+            mCount = 0;
+        }
+
+        @Override
+        public void write(int b) throws IOException {
+            try {
+                mSignature.update((byte) b);
+            } catch (SignatureException e) {
+                throw new IOException("SignatureException: " + e);
+            }
+            super.write(b);
+            mCount++;
+        }
+
+        @Override
+        public void write(byte[] b, int off, int len) throws IOException {
+            try {
+                mSignature.update(b, off, len);
+            } catch (SignatureException e) {
+                throw new IOException("SignatureException: " + e);
+            }
+            super.write(b, off, len);
+            mCount += len;
+        }
+
+        public int size() {
+            return mCount;
+        }
+    }
+
+    /** Write a .SF file with a digest of the specified manifest. */
+    private static void writeSignatureFile(Manifest manifest, SignatureOutputStream out)
+            throws IOException, GeneralSecurityException {
+        Manifest sf = new Manifest();
+        Attributes main = sf.getMainAttributes();
+        main.putValue("Signature-Version", "1.0");
+        main.putValue("Created-By", "1.0 (Android SignApk)");
+
+        BASE64Encoder base64 = new BASE64Encoder();
+        MessageDigest md = MessageDigest.getInstance("SHA1");
+        PrintStream print = new PrintStream(
+                new DigestOutputStream(new ByteArrayOutputStream(), md),
+                true, "UTF-8");
+
+        // Digest of the entire manifest
+        manifest.write(print);
+        print.flush();
+        main.putValue("SHA1-Digest-Manifest", base64.encode(md.digest()));
+
+        Map<String, Attributes> entries = manifest.getEntries();
+        for (Map.Entry<String, Attributes> entry : entries.entrySet()) {
+            // Digest of the manifest stanza for this entry.
+            print.print("Name: " + entry.getKey() + "\r\n");
+            for (Map.Entry<Object, Object> att : entry.getValue().entrySet()) {
+                print.print(att.getKey() + ": " + att.getValue() + "\r\n");
+            }
+            print.print("\r\n");
+            print.flush();
+
+            Attributes sfAttr = new Attributes();
+            sfAttr.putValue("SHA1-Digest", base64.encode(md.digest()));
+            sf.getEntries().put(entry.getKey(), sfAttr);
+        }
+
+        sf.write(out);
+
+        // A bug in the java.util.jar implementation of Android platforms
+        // up to version 1.6 will cause a spurious IOException to be thrown
+        // if the length of the signature file is a multiple of 1024 bytes.
+        // As a workaround, add an extra CRLF in this case.
+        if ((out.size() % 1024) == 0) {
+            out.write('\r');
+            out.write('\n');
+        }
+    }
+
+    /** Write a .RSA file with a digital signature. */
+    private static void writeSignatureBlock(
+            Signature signature, X509Certificate publicKey, OutputStream out)
+            throws IOException, GeneralSecurityException {
+        SignerInfo signerInfo = new SignerInfo(
+                new X500Name(publicKey.getIssuerX500Principal().getName()),
+                publicKey.getSerialNumber(),
+                AlgorithmId.get("SHA1"),
+                AlgorithmId.get("RSA"),
+                signature.sign());
+
+        PKCS7 pkcs7 = new PKCS7(
+                new AlgorithmId[] { AlgorithmId.get("SHA1") },
+                new ContentInfo(ContentInfo.DATA_OID, null),
+                new X509Certificate[] { publicKey },
+                new SignerInfo[] { signerInfo });
+
+        pkcs7.encodeSignedData(out);
+    }
+
+    private static void signWholeOutputFile(byte[] zipData,
+                                            OutputStream outputStream,
+                                            X509Certificate publicKey,
+                                            PrivateKey privateKey)
+        throws IOException, GeneralSecurityException {
+
+        // For a zip with no archive comment, the
+        // end-of-central-directory record will be 22 bytes long, so
+        // we expect to find the EOCD marker 22 bytes from the end.
+        if (zipData[zipData.length-22] != 0x50 ||
+            zipData[zipData.length-21] != 0x4b ||
+            zipData[zipData.length-20] != 0x05 ||
+            zipData[zipData.length-19] != 0x06) {
+            throw new IllegalArgumentException("zip data already has an archive comment");
+        }
+
+        Signature signature = Signature.getInstance("SHA1withRSA");
+        signature.initSign(privateKey);
+        signature.update(zipData, 0, zipData.length-2);
+
+        ByteArrayOutputStream temp = new ByteArrayOutputStream();
+
+        // put a readable message and a null char at the start of the
+        // archive comment, so that tools that display the comment
+        // (hopefully) show something sensible.
+        // TODO: anything more useful we can put in this message?
+        byte[] message = "signed by SignApk".getBytes("UTF-8");
+        temp.write(message);
+        temp.write(0);
+        writeSignatureBlock(signature, publicKey, temp);
+        int total_size = temp.size() + 6;
+        if (total_size > 0xffff) {
+            throw new IllegalArgumentException("signature is too big for ZIP file comment");
+        }
+        // signature starts this many bytes from the end of the file
+        int signature_start = total_size - message.length - 1;
+        temp.write(signature_start & 0xff);
+        temp.write((signature_start >> 8) & 0xff);
+        // Why the 0xff bytes?  In a zip file with no archive comment,
+        // bytes [-6:-2] of the file are the little-endian offset from
+        // the start of the file to the central directory.  So for the
+        // two high bytes to be 0xff 0xff, the archive would have to
+        // be nearly 4GB in side.  So it's unlikely that a real
+        // commentless archive would have 0xffs here, and lets us tell
+        // an old signed archive from a new one.
+        temp.write(0xff);
+        temp.write(0xff);
+        temp.write(total_size & 0xff);
+        temp.write((total_size >> 8) & 0xff);
+        temp.flush();
+
+        // Signature verification checks that the EOCD header is the
+        // last such sequence in the file (to avoid minzip finding a
+        // fake EOCD appended after the signature in its scan).  The
+        // odds of producing this sequence by chance are very low, but
+        // let's catch it here if it does.
+        byte[] b = temp.toByteArray();
+        for (int i = 0; i < b.length-3; ++i) {
+            if (b[i] == 0x50 && b[i+1] == 0x4b && b[i+2] == 0x05 && b[i+3] == 0x06) {
+                throw new IllegalArgumentException("found spurious EOCD header at " + i);
+            }
+        }
+
+        outputStream.write(zipData, 0, zipData.length-2);
+        outputStream.write(total_size & 0xff);
+        outputStream.write((total_size >> 8) & 0xff);
+        temp.writeTo(outputStream);
+    }
+
+    /**
+     * Copy all the files in a manifest from input to output.  We set
+     * the modification times in the output to a fixed time, so as to
+     * reduce variation in the output file and make incremental OTAs
+     * more efficient.
+     */
+    private static void copyFiles(Manifest manifest,
+        JarFile in, JarOutputStream out, long timestamp) throws IOException {
+        byte[] buffer = new byte[4096];
+        int num;
+
+        Map<String, Attributes> entries = manifest.getEntries();
+        List<String> names = new ArrayList(entries.keySet());
+        Collections.sort(names);
+        for (String name : names) {
+            JarEntry inEntry = in.getJarEntry(name);
+            JarEntry outEntry = null;
+            if (inEntry.getMethod() == JarEntry.STORED) {
+                // Preserve the STORED method of the input entry.
+                outEntry = new JarEntry(inEntry);
+            } else {
+                // Create a new entry so that the compressed len is recomputed.
+                outEntry = new JarEntry(name);
+            }
+            outEntry.setTime(timestamp);
+            out.putNextEntry(outEntry);
+
+            InputStream data = in.getInputStream(inEntry);
+            while ((num = data.read(buffer)) > 0) {
+                out.write(buffer, 0, num);
+            }
+            out.flush();
+        }
+    }
+
+    public static void main(String[] args) {
+        if (args.length != 4 && args.length != 5) {
+            System.err.println("Usage: signapk [-w] " +
+                    "publickey.x509[.pem] privatekey.pk8 " +
+                    "input.jar output.jar");
+            System.exit(2);
+        }
+
+        boolean signWholeFile = false;
+        int argstart = 0;
+        if (args[0].equals("-w")) {
+            signWholeFile = true;
+            argstart = 1;
+        }
+
+        JarFile inputJar = null;
+        JarOutputStream outputJar = null;
+        FileOutputStream outputFile = null;
+
+        try {
+            X509Certificate publicKey = readPublicKey(new File(args[argstart+0]));
+
+            // Assume the certificate is valid for at least an hour.
+            long timestamp = publicKey.getNotBefore().getTime() + 3600L * 1000;
+
+            PrivateKey privateKey = readPrivateKey(new File(args[argstart+1]));
+            inputJar = new JarFile(new File(args[argstart+2]), false);  // Don't verify.
+
+            OutputStream outputStream = null;
+            if (signWholeFile) {
+                outputStream = new ByteArrayOutputStream();
+            } else {
+                outputStream = outputFile = new FileOutputStream(args[argstart+3]);
+            }
+            outputJar = new JarOutputStream(outputStream);
+            outputJar.setLevel(9);
+
+            JarEntry je;
+
+            // MANIFEST.MF
+            Manifest manifest = addDigestsToManifest(inputJar);
+            je = new JarEntry(JarFile.MANIFEST_NAME);
+            je.setTime(timestamp);
+            outputJar.putNextEntry(je);
+            manifest.write(outputJar);
+
+            // CERT.SF
+            Signature signature = Signature.getInstance("SHA1withRSA");
+            signature.initSign(privateKey);
+            je = new JarEntry(CERT_SF_NAME);
+            je.setTime(timestamp);
+            outputJar.putNextEntry(je);
+            writeSignatureFile(manifest,
+                    new SignatureOutputStream(outputJar, signature));
+
+            // CERT.RSA
+            je = new JarEntry(CERT_RSA_NAME);
+            je.setTime(timestamp);
+            outputJar.putNextEntry(je);
+            writeSignatureBlock(signature, publicKey, outputJar);
+
+            // Everything else
+            copyFiles(manifest, inputJar, outputJar, timestamp);
+
+            outputJar.close();
+            outputJar = null;
+            outputStream.flush();
+
+            if (signWholeFile) {
+                outputFile = new FileOutputStream(args[argstart+3]);
+                signWholeOutputFile(((ByteArrayOutputStream)outputStream).toByteArray(),
+                                    outputFile, publicKey, privateKey);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            System.exit(1);
+        } finally {
+            try {
+                if (inputJar != null) inputJar.close();
+                if (outputFile != null) outputFile.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+                System.exit(1);
+            }
+        }
+    }
+}
diff --git a/build/tools/signapk/SignApk.mf b/build/tools/signapk/SignApk.mf
new file mode 100644 (file)
index 0000000..2c72e59
--- /dev/null
@@ -0,0 +1 @@
+Main-Class: com.android.signapk.SignApk
diff --git a/build/tools/signapk/test/run b/build/tools/signapk/test/run
new file mode 100644 (file)
index 0000000..4e24625
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/make -f
+
+package := NotePad.apk
+
+all: out/signed-$(package)
+
+clean:
+       rm -rf out
+
+.PHONY: FORCE
+
+DSAPARAM := out/dsaparam
+$(DSAPARAM):
+       mkdir -p $(dir $@)
+       umask 0077 && openssl dsaparam -out $@ 1024
+
+%.pem: $(DSAPARAM) FORCE
+       mkdir -p $(dir $@)
+       umask 0077 && openssl gendsa -out $@.pk~ $(DSAPARAM)
+       umask 0077 && openssl pkcs8 -topk8 -nocrypt \
+               -in $@.pk~ -out $@.pk
+       umask 0077 && openssl req -new -x509 -key $@.pk -out $@ -days 1095 \
+           -subj "/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com"
+
+cert := out/key1.pem
+out/signed-$(package): $(package) $(cert)
+       mkdir -p $(dir $@)
+       SIGNAPK_DEBUG=1 \
+       signapk -input $< -output $@ \
+               -key $(cert).pk -cert $(cert) -tempdir out
diff --git a/build/tools/soslim/Android.mk b/build/tools/soslim/Android.mk
new file mode 100644 (file)
index 0000000..60a860a
--- /dev/null
@@ -0,0 +1,49 @@
+# Copyright 2005 The Android Open Source Project
+#
+# Android.mk for soslim
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+ifeq ($(TARGET_ARCH),arm)
+include $(CLEAR_VARS)
+
+LOCAL_LDLIBS += -ldl
+LOCAL_CFLAGS += -O2 -g
+LOCAL_CFLAGS += -fno-function-sections -fno-data-sections -fno-inline
+LOCAL_CFLAGS += -Wall -Wno-unused-function #-Werror
+LOCAL_CFLAGS += -DBIG_ENDIAN=1
+LOCAL_CFLAGS += -DARM_SPECIFIC_HACKS
+LOCAL_CFLAGS += -DSUPPORT_ANDROID_PRELINK_TAGS
+LOCAL_CFLAGS += -DDEBUG
+LOCAL_CFLAGS += -DSTRIP_STATIC_SYMBOLS
+LOCAL_CFLAGS += -DMOVE_SECTIONS_IN_RANGES
+
+ifeq ($(HOST_OS),windows)
+# Cygwin stat does not support ACCESSPERMS bitmask
+LOCAL_CFLAGS += -DACCESSPERMS=0777
+LOCAL_LDLIBS += -lintl
+endif
+
+LOCAL_SRC_FILES := \
+        cmdline.c \
+        common.c \
+        debug.c \
+        soslim.c \
+        main.c \
+        prelink_info.c \
+        symfilter.c
+
+LOCAL_C_INCLUDES:= \
+       $(LOCAL_PATH)/ \
+       external/elfutils/lib/ \
+       external/elfutils/libelf/ \
+       external/elfutils/libebl/ \
+       external/elfcopy/
+
+LOCAL_STATIC_LIBRARIES := libelfcopy libelf libebl libebl_arm #dl
+
+LOCAL_MODULE := soslim
+
+include $(BUILD_HOST_EXECUTABLE)
+endif #TARGET_ARCH==arm
diff --git a/build/tools/soslim/cmdline.c b/build/tools/soslim/cmdline.c
new file mode 100644 (file)
index 0000000..c2d5e71
--- /dev/null
@@ -0,0 +1,141 @@
+#include <debug.h>
+#include <cmdline.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <ctype.h>
+
+extern char *optarg;
+extern int optind, opterr, optopt;
+
+static struct option long_options[] =
+{
+    {"verbose",  no_argument,       0, 'V'},
+    {"quiet",    no_argument,       0, 'Q'},
+    {"shady",    no_argument,       0, 'S'},
+    {"print",    no_argument,       0, 'p'},
+    {"help",     no_argument,       0, 'h'},
+    {"outfile",  required_argument, 0, 'o'},
+    {"filter",   required_argument, 0, 'f'},
+    {"dry",      no_argument,       0, 'n'},
+    {"strip",    no_argument,       0, 's'},
+    {0, 0, 0, 0},
+};
+
+/* This array must parallel long_options[] */
+static
+const char *descriptions[sizeof(long_options)/sizeof(long_options[0])] = {
+       "print verbose output",
+    "suppress errors and warnings",
+    "patch ABS symbols whose values coincide with section starts and ends",
+    "print the symbol table (if specified, only -V is allowed)",
+    "this help screen",
+    "specify an output file (if not provided, input file is modified)",
+    "specify a symbol-filter file",
+    "dry run (perform all calculations but do not modify the ELF file)",
+    "strip debug sections, if they are present"
+};
+
+void print_help(void)
+{
+    fprintf(stdout,
+                       "invokation:\n"
+                       "\tsoslim file1 [file2 file3 ... fileN] [-Ldir1 -Ldir2 ... -LdirN] "
+                       "[-Vpn]\n"
+                       "or\n"
+                       "\tsoslim -h\n\n");
+       fprintf(stdout, "options:\n");
+       struct option *opt = long_options;
+       const char **desc = descriptions;
+       while (opt->name) {
+               fprintf(stdout, "\t-%c/--%-15s %s\n",
+                               opt->val,
+                               opt->name,
+                               *desc);
+               opt++;
+               desc++;
+       }
+}
+
+int get_options(int argc, char **argv,
+                char **outfile,
+                char **symsfile,
+                int *print_symtab,
+                int *verbose,
+                int *quiet,
+                int *shady,
+                int *dry_run,
+                int *strip_debug)
+{
+    int c;
+
+    ASSERT(outfile);
+    *outfile = NULL;
+    ASSERT(symsfile);
+    *symsfile = NULL;
+    ASSERT(print_symtab);
+    *print_symtab = 0;
+    ASSERT(verbose);
+    *verbose = 0;
+    ASSERT(quiet);
+    *quiet = 0;
+    ASSERT(shady);
+    *shady = 0;
+    ASSERT(dry_run);
+    *dry_run = 0;
+    ASSERT(strip_debug);
+    *strip_debug = 0;
+
+    while (1) {
+        /* getopt_long stores the option index here. */
+        int option_index = 0;
+
+        c = getopt_long (argc, argv,
+                         "QVSphi:o:y:Y:f:ns",
+                         long_options,
+                         &option_index);
+        /* Detect the end of the options. */
+        if (c == -1) break;
+
+        if (isgraph(c)) {
+            INFO ("option -%c with value `%s'\n", c, (optarg ?: "(null)"));
+        }
+
+#define SET_STRING_OPTION(name) do { \
+    ASSERT(optarg);                  \
+    *name = strdup(optarg);          \
+} while(0)
+
+        switch (c) {
+        case 0:
+            /* If this option set a flag, do nothing else now. */
+            if (long_options[option_index].flag != 0)
+                break;
+            INFO ("option %s", long_options[option_index].name);
+            if (optarg)
+                INFO (" with arg %s", optarg);
+            INFO ("\n");
+            break;
+        case 'p': *print_symtab = 1; break;
+        case 'h': print_help(); exit(1); break;
+        case 'V': *verbose = 1; break;
+        case 'Q': *quiet = 1; break;
+        case 'S': *shady = 1; break;
+        case 'n': *dry_run = 1; break;
+        case 's': *strip_debug = 1; break;
+        case 'o': SET_STRING_OPTION(outfile); break;
+        case 'f': SET_STRING_OPTION(symsfile); break;
+        case '?':
+            /* getopt_long already printed an error message. */
+            break;
+
+#undef SET_STRING_OPTION
+
+        default:
+            FAILIF(1, "Unknown option");
+        }
+    }
+
+    return optind;
+}
diff --git a/build/tools/soslim/cmdline.h b/build/tools/soslim/cmdline.h
new file mode 100644 (file)
index 0000000..bfc431e
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef CMDLINE_H
+#define CMDLINE_H
+
+void print_help(void);
+
+int get_options(int argc, char **argv,
+                char **outfile,
+                char **symsfile,
+                int *print_symtab,
+                int *verbose,
+                int *quiet,
+                int *shady,
+                int *dry_run,
+                int *strip_debug);
+
+#endif/*CMDLINE_H*/
diff --git a/build/tools/soslim/common.c b/build/tools/soslim/common.c
new file mode 100644 (file)
index 0000000..b90cf41
--- /dev/null
@@ -0,0 +1,35 @@
+#include <stdlib.h>
+#include <common.h>
+#include <debug.h>
+
+void map_over_sections(Elf *elf, 
+                       section_match_fn_t match,
+                       void *user_data)
+{
+    Elf_Scn* section = NULL;
+    while ((section = elf_nextscn(elf, section)) != NULL) {
+        if (match(elf, section, user_data))
+            return;
+    }
+}   
+
+void map_over_segments(Elf *elf, 
+                       segment_match_fn_t match, 
+                       void *user_data)
+{
+    Elf32_Ehdr *ehdr; 
+    Elf32_Phdr *phdr; 
+    int index;
+
+    ehdr = elf32_getehdr(elf);
+    phdr = elf32_getphdr(elf);
+
+    INFO("Scanning over %d program segments...\n", 
+         ehdr->e_phnum);
+
+    for (index = ehdr->e_phnum; index; index--) {
+        if (match(elf, phdr++, user_data))
+            return;
+    }
+}
+
diff --git a/build/tools/soslim/common.h b/build/tools/soslim/common.h
new file mode 100644 (file)
index 0000000..dacf930
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <libelf.h>
+#include <elf.h>
+
+#define unlikely(expr) __builtin_expect (expr, 0)
+#define likely(expr)   __builtin_expect (expr, 1)
+
+#define MIN(a,b) ((a)<(b)?(a):(b)) /* no side effects in arguments allowed! */
+
+typedef int (*section_match_fn_t)(Elf *, Elf_Scn *, void *);
+void map_over_sections(Elf *, section_match_fn_t, void *);
+
+typedef int (*segment_match_fn_t)(Elf *, Elf32_Phdr *, void *);
+void map_over_segments(Elf *, segment_match_fn_t, void *);
+
+typedef struct {
+    Elf_Scn *sect;
+    Elf32_Shdr *hdr;
+    Elf_Data *data;
+    size_t index;
+} section_info_t;
+
+static inline void get_section_info(Elf_Scn *sect, section_info_t *info)
+{
+    info->sect = sect;
+    info->data = elf_getdata(sect, 0);
+    info->hdr = elf32_getshdr(sect);
+    info->index = elf_ndxscn(sect);
+}
+
+static inline int is_host_little(void)
+{
+    short val = 0x10;
+    return ((char *)&val)[0] != 0;
+}
+
+static inline long switch_endianness(long val)
+{
+       long newval;
+       ((char *)&newval)[3] = ((char *)&val)[0];
+       ((char *)&newval)[2] = ((char *)&val)[1];
+       ((char *)&newval)[1] = ((char *)&val)[2];
+       ((char *)&newval)[0] = ((char *)&val)[3];
+       return newval;
+}
+
+#endif/*COMMON_H*/
diff --git a/build/tools/soslim/debug.c b/build/tools/soslim/debug.c
new file mode 100644 (file)
index 0000000..b8365af
--- /dev/null
@@ -0,0 +1,40 @@
+#include <debug.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#if 0
+
+#define NUM_COLS  (32)
+
+int dump_hex_buffer(FILE *s, void *b, size_t len, size_t elsize) {
+    int num_nonprintable = 0;
+    int i, last;
+    char *pchr = (char *)b;
+    fputc('\n', s);
+    for (i = last = 0; i < len; i++) {
+        if (!elsize) {
+            if (i && !(i % 4)) fprintf(s, " ");
+            if (i && !(i % 8)) fprintf(s, " ");
+        } else {
+            if (i && !(i % elsize)) fprintf(s, " ");
+        }
+
+        if (i && !(i % NUM_COLS)) {
+            while (last < i) {
+                if (isprint(pchr[last]))
+                    fputc(pchr[last], s);
+                else {
+                    fputc('.', s);
+                    num_nonprintable++;
+                }
+                last++;
+            }
+            fprintf(s, " (%d)\n", i);
+        }
+        fprintf(s, "%02x", (unsigned char)pchr[i]);
+    }
+    if (i && (i % NUM_COLS)) fputs("\n", s);
+    return num_nonprintable;
+}
+
+#endif
diff --git a/build/tools/soslim/debug.h b/build/tools/soslim/debug.h
new file mode 100644 (file)
index 0000000..e7a2f9a
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <common.h>
+
+#ifdef DEBUG
+
+    #define FAILIF(cond, msg...) do {                        \
+       if (unlikely(cond)) {                                \
+        fprintf(stderr, "%s(%d): ", __FILE__, __LINE__); \
+               fprintf(stderr, ##msg);                          \
+               exit(1);                                         \
+       }                                                    \
+} while(0)
+
+/* Debug enabled */
+    #define ASSERT(x) do {                                \
+       if (unlikely(!(x))) {                             \
+               fprintf(stderr,                               \
+                               "ASSERTION FAILURE %s:%d: [%s]\n",    \
+                               __FILE__, __LINE__, #x);              \
+               exit(1);                                      \
+       }                                                 \
+} while(0)
+
+#else
+
+    #define FAILIF(cond, msg...) do { \
+       if (unlikely(cond)) {         \
+               fprintf(stderr, ##msg);   \
+               exit(1);                  \
+       }                             \
+} while(0)
+
+/* No debug */
+    #define ASSERT(x)   do { } while(0)
+
+#endif/* DEBUG */
+
+#define FAILIF_LIBELF(cond, function) \
+    FAILIF(cond, "%s(): %s\n", #function, elf_errmsg(elf_errno()));
+
+static inline void *MALLOC(unsigned int size) {
+    void *m = malloc(size);
+    FAILIF(NULL == m, "malloc(%d) failed!\n", size);
+    return m;
+}
+
+static inline void *CALLOC(unsigned int num_entries, unsigned int entry_size) {
+    void *m = calloc(num_entries, entry_size);
+    FAILIF(NULL == m, "calloc(%d, %d) failed!\n", num_entries, entry_size);
+    return m;
+}
+
+static inline void *REALLOC(void *ptr, unsigned int size) {
+    void *m = realloc(ptr, size);
+    FAILIF(NULL == m, "realloc(%p, %d) failed!\n", ptr, size);
+    return m;
+}
+
+static inline void FREE(void *ptr) {
+    free(ptr);
+}
+
+static inline void FREEIF(void *ptr) {
+    if (ptr) FREE(ptr);
+}
+
+#define PRINT(x...)  do {                             \
+    extern int quiet_flag;                            \
+    if(likely(!quiet_flag))                           \
+        fprintf(stdout, ##x);                         \
+} while(0)
+
+#define ERROR(x...) fprintf(stderr, ##x)
+
+#define INFO(x...)  do {                              \
+    extern int verbose_flag;                          \
+    if(unlikely(verbose_flag))                        \
+        fprintf(stdout, ##x);                         \
+} while(0)
+
+/* Prints a hex and ASCII dump of the selected buffer to the selected stream. */
+int dump_hex_buffer(FILE *s, void *b, size_t l, size_t elsize);
+
+#endif/*DEBUG_H*/
diff --git a/build/tools/soslim/main.c b/build/tools/soslim/main.c
new file mode 100644 (file)
index 0000000..dd8a60b
--- /dev/null
@@ -0,0 +1,360 @@
+/* TODO:
+   1. check the ARM EABI version--this works for versions 1 and 2.
+   2. use a more-intelligent approach to finding the symbol table, symbol-string
+      table, and the .dynamic section.
+   3. fix the determination of the host and ELF-file endianness
+   4. write the help screen
+*/
+
+#include <stdio.h>
+#include <common.h>
+#include <debug.h>
+#include <hash.h>
+#include <libelf.h>
+#include <elf.h>
+#include <gelf.h>
+#include <cmdline.h>
+#include <string.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <soslim.h>
+#include <symfilter.h>
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+#include <prelink_info.h>
+#endif
+
+/* Flag set by --verbose.  This variable is global as it is accessed by the
+   macro INFO() in multiple compilation unites. */
+int verbose_flag = 0;
+/* Flag set by --quiet.  This variable is global as it is accessed by the
+   macro PRINT() in multiple compilation unites. */
+int quiet_flag = 0;
+static void print_dynamic_symbols(Elf *elf, const char *symtab_name);
+
+int main(int argc, char **argv)
+{
+    int elf_fd = -1, newelf_fd = -1;
+    Elf *elf = NULL, *newelf = NULL;
+    char *infile = NULL;
+    char *outfile = NULL;
+    char *symsfile_name = NULL;
+    int print_symtab = 0;
+    int shady = 0;
+    int dry_run = 0;
+    int strip_debug = 0;
+
+    /* Do not issue INFO() statements before you call get_options() to set
+       the verbose flag as necessary.
+    */
+
+    int first = get_options(argc, argv,
+                            &outfile,
+                            &symsfile_name,
+                            &print_symtab,
+                            &verbose_flag,
+                            &quiet_flag,
+                            &shady,
+                            &dry_run,
+                            &strip_debug);
+
+    if ((print_symtab && (first == argc)) ||
+        (!print_symtab && first + 1 != argc)) {
+        print_help();
+        FAILIF(1,  "You must specify an input ELF file!\n");
+    }
+    FAILIF(print_symtab && (outfile || symsfile_name || shady),
+           "You cannot provide --print and --outfile, --filter options, or "
+           "--shady simultaneously!\n");
+    FAILIF(dry_run && outfile,
+           "You cannot have a dry run and output a file at the same time.");
+
+    /* Check to see whether the ELF library is current. */
+    FAILIF (elf_version(EV_CURRENT) == EV_NONE, "libelf is out of date!\n");
+
+    if (print_symtab) {
+
+        while (first < argc) {
+            infile = argv[first++];
+
+            INFO("Opening %s...\n", infile);
+            elf_fd = open(infile, O_RDONLY);
+            FAILIF(elf_fd < 0, "open(%s): %s (%d)\n",
+                   infile,
+                   strerror(errno),
+                   errno);
+            INFO("Calling elf_begin(%s)...\n", infile);
+            elf = elf_begin(elf_fd, ELF_C_READ, NULL);
+            FAILIF_LIBELF(elf == NULL, elf_begin);
+
+            /* libelf can recognize COFF and A.OUT formats, but we handle only
+               ELF. */
+            FAILIF(elf_kind(elf) != ELF_K_ELF,
+                   "Input file %s is not in ELF format!\n",
+                   infile);
+
+            /* Make sure this is a shared library or an executable. */
+            {
+                GElf_Ehdr elf_hdr;
+                INFO("Making sure %s is a shared library or an executable.\n",
+                     infile);
+                FAILIF_LIBELF(0 == gelf_getehdr(elf, &elf_hdr), gelf_getehdr);
+                FAILIF(elf_hdr.e_type != ET_DYN &&
+                       elf_hdr.e_type != ET_EXEC,
+                       "%s must be a shared library or an executable "
+                       "(elf type is %d).\n",
+                       infile,
+                       elf_hdr.e_type);
+            }
+
+            print_dynamic_symbols(elf, infile);
+
+            FAILIF_LIBELF(elf_end(elf), elf_end);
+            FAILIF(close(elf_fd) < 0, "Could not close file %s: %s (%d)!\n",
+                   infile, strerror(errno), errno);
+        }
+    }
+    else {
+        int elf_fd = -1;
+        Elf *elf = NULL;
+        infile = argv[first];
+
+        INFO("Opening %s...\n", infile);
+        elf_fd = open(infile, ((outfile == NULL && dry_run == 0) ? O_RDWR : O_RDONLY));
+        FAILIF(elf_fd < 0, "open(%s): %s (%d)\n",
+               infile,
+               strerror(errno),
+               errno);
+        INFO("Calling elf_begin(%s)...\n", infile);
+        elf = elf_begin(elf_fd,
+                        ((outfile == NULL && dry_run == 0) ? ELF_C_RDWR : ELF_C_READ),
+                        NULL);
+        FAILIF_LIBELF(elf == NULL, elf_begin);
+
+        /* libelf can recognize COFF and A.OUT formats, but we handle only ELF. */
+        FAILIF(elf_kind(elf) != ELF_K_ELF,
+               "Input file %s is not in ELF format!\n",
+               infile);
+
+        /* We run a better check in adjust_elf() itself.  It is permissible to call adjust_elf()
+           on an executable if we are only stripping sections from the executable, not rearranging
+           or moving sections.
+        */
+        if (0) {
+            /* Make sure this is a shared library. */
+            GElf_Ehdr elf_hdr;
+            INFO("Making sure %s is a shared library...\n", infile);
+            FAILIF_LIBELF(0 == gelf_getehdr(elf, &elf_hdr), gelf_getehdr);
+            FAILIF(elf_hdr.e_type != ET_DYN,
+                   "%s must be a shared library (elf type is %d, expecting %d).\n",
+                   infile,
+                   elf_hdr.e_type,
+                   ET_DYN);
+        }
+
+        if (outfile != NULL) {
+            ASSERT(!dry_run);
+            struct stat st;
+            FAILIF(fstat (elf_fd, &st) != 0,
+                   "Cannot stat input file %s: %s (%d)!\n",
+                   infile, strerror(errno), errno);
+            newelf_fd = open (outfile, O_RDWR | O_CREAT | O_TRUNC,
+                    st.st_mode & ACCESSPERMS);
+            FAILIF(newelf_fd < 0, "Cannot create file %s: %s (%d)!\n",
+                   outfile, strerror(errno), errno);
+            INFO("Output file is [%s].\n", outfile);
+            newelf = elf_begin(newelf_fd, ELF_C_WRITE_MMAP, NULL);
+        } else {
+            INFO("Modifying [%s] in-place.\n", infile);
+            newelf = elf_clone(elf, ELF_C_EMPTY);
+        }
+
+        symfilter_t symfilter;
+
+        symfilter.symbols_to_keep = NULL;
+        symfilter.num_symbols_to_keep = 0;
+        if (symsfile_name) {
+            /* Make sure that the file is not empty. */
+            struct stat s;
+            FAILIF(stat(symsfile_name, &s) < 0,
+                   "Cannot stat file %s.\n", symsfile_name);
+            if (s.st_size) {
+                INFO("Building symbol filter.\n");
+                build_symfilter(symsfile_name, elf, &symfilter, s.st_size);
+            }
+            else INFO("Not building symbol filter, filter file is empty.\n");
+        }
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+        int prelinked = 0;
+        int elf_little; /* valid if prelinked != 0 */
+        long prelink_addr; /* valid if prelinked != 0 */
+#endif
+        clone_elf(elf, newelf,
+                  infile, outfile,
+                  symfilter.symbols_to_keep,
+                  symfilter.num_symbols_to_keep,
+                  shady
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+                  , &prelinked,
+                  &elf_little,
+                  &prelink_addr
+#endif
+                  ,
+                  true, /* rebuild the section-header-strings table */
+                  strip_debug,
+                  dry_run);
+
+        if (symsfile_name && symfilter.symbols_to_keep != NULL) {
+            destroy_symfilter(&symfilter);
+        }
+
+        if (outfile != NULL) INFO("Closing %s...\n", outfile);
+        FAILIF_LIBELF(elf_end (newelf) != 0, elf_end);
+        FAILIF(newelf_fd >= 0 && close(newelf_fd) < 0,
+               "Could not close file %s: %s (%d)!\n",
+               outfile, strerror(errno), errno);
+
+        INFO("Closing %s...\n", infile);
+        FAILIF_LIBELF(elf_end(elf), elf_end);
+        FAILIF(close(elf_fd) < 0, "Could not close file %s: %s (%d)!\n",
+               infile, strerror(errno), errno);
+
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+        if (prelinked) {
+            INFO("File is prelinked, putting prelink TAG back in place.\n");
+            setup_prelink_info(outfile != NULL ? outfile : infile,
+                               elf_little,
+                               prelink_addr);
+        }
+#endif
+    }
+
+    FREEIF(outfile);
+    return 0;
+}
+
+static void print_dynamic_symbols(Elf *elf, const char *file)
+{
+    Elf_Scn *scn = NULL;
+    GElf_Shdr shdr;
+
+    GElf_Ehdr ehdr;
+    FAILIF_LIBELF(0 == gelf_getehdr(elf, &ehdr), gelf_getehdr);
+    while ((scn = elf_nextscn (elf, scn)) != NULL) {
+        FAILIF_LIBELF(NULL == gelf_getshdr(scn, &shdr), gelf_getshdr);
+        if (SHT_DYNSYM == shdr.sh_type) {
+            /* This failure is too restrictive.  There is no reason why
+               the symbol table couldn't be called something else, but
+               there is a standard name, and chances are that if we don't
+               see it, there's something wrong.
+            */
+            size_t shstrndx;
+            FAILIF_LIBELF(elf_getshstrndx(elf, &shstrndx) < 0,
+                          elf_getshstrndx);
+            /* Now print the symbols. */
+            {
+                Elf_Data *symdata;
+                size_t elsize;
+                symdata = elf_getdata (scn, NULL); /* get the symbol data */
+                FAILIF_LIBELF(NULL == symdata, elf_getdata);
+                /* Get the number of section.  We need to compare agains this
+                   value for symbols that have special info in their section
+                   references */
+                size_t shnum;
+                FAILIF_LIBELF(elf_getshnum (elf, &shnum) < 0, elf_getshnum);
+                /* Retrieve the size of a symbol entry */
+                elsize = gelf_fsize(elf, ELF_T_SYM, 1, ehdr.e_version);
+
+                size_t index;
+                for (index = 0; index < symdata->d_size / elsize; index++) {
+                    GElf_Sym sym_mem;
+                    GElf_Sym *sym;
+                    /* Get the symbol. */
+                    sym = gelf_getsymshndx (symdata, NULL,
+                                            index, &sym_mem, NULL);
+                    FAILIF_LIBELF(sym == NULL, gelf_getsymshndx);
+                    /* Print the symbol. */
+                    char bind = '?';
+                    switch(ELF32_ST_BIND(sym->st_info))
+                    {
+                    case STB_LOCAL: bind = 'l'; break;
+                    case STB_GLOBAL: bind = 'g'; break;
+                    case STB_WEAK: bind = 'w'; break;
+                    default: break;
+                    }
+                    char type = '?';
+                    switch(ELF32_ST_TYPE(sym->st_info))
+                    {
+                    case STT_NOTYPE: /* Symbol type is unspecified */
+                        type = '?';
+                        break;
+                    case STT_OBJECT: /* Symbol is a data object */
+                        type = 'o';
+                        break;
+                    case STT_FUNC: /* Symbol is a code object */
+                        type = 'f';
+                        break;
+                    case STT_SECTION:/* Symbol associated with a section */
+                        type = 's';
+                        break;
+                    case STT_FILE: /* Symbol's name is file name */
+                        type = 'f';
+                        break;
+                    case STT_COMMON: /* Symbol is a common data object */
+                        type = 'c';
+                        break;
+                    case STT_TLS: /* Symbol is thread-local data object*/
+                        type = 't';
+                        break;
+                    }
+                    {
+                        int till_lineno;
+                        int lineno;
+                        const char *section_name = "(unknown)";
+                        FAILIF(sym->st_shndx == SHN_XINDEX,
+                               "Can't handle symbol's st_shndx == SHN_XINDEX!\n");
+                        if (sym->st_shndx != SHN_UNDEF &&
+                            sym->st_shndx < shnum) {
+                            Elf_Scn *symscn = elf_getscn(elf, sym->st_shndx);
+                            FAILIF_LIBELF(NULL == symscn, elf_getscn);
+                            GElf_Shdr symscn_shdr;
+                            FAILIF_LIBELF(NULL == gelf_getshdr(symscn,
+                                                               &symscn_shdr),
+                                          gelf_getshdr);
+                            section_name = elf_strptr(elf, shstrndx,
+                                                      symscn_shdr.sh_name);
+                        }
+                        else if (sym->st_shndx == SHN_ABS) {
+                            section_name = "SHN_ABS";
+                        }
+                        else if (sym->st_shndx == SHN_COMMON) {
+                            section_name = "SHN_COMMON";
+                        }
+                        else if (sym->st_shndx == SHN_UNDEF) {
+                            section_name = "(undefined)";
+                        }
+                        /* value size binding type section symname */
+                        PRINT("%-15s %8zd: %08llx %08llx %c%c %5d %n%s%n",
+                              file,
+                              index,
+                              sym->st_value, sym->st_size, bind, type,
+                              sym->st_shndx,
+                              &till_lineno,
+                              section_name,
+                              &lineno);
+                        lineno -= till_lineno;
+                        /* Create padding for section names of 15 chars.
+                           This limit is somewhat arbitratry. */
+                        while (lineno++ < 15) PRINT(" ");
+                        PRINT("(%d) %s\n",
+                              sym->st_name,
+                              elf_strptr(elf, shdr.sh_link, sym->st_name));
+                    }
+                }
+            }
+        } /* if (shdr.sh_type = SHT_DYNSYM) */
+    } /* while ((scn = elf_nextscn (elf, scn)) != NULL) */
+}
diff --git a/build/tools/soslim/prelink_info.c b/build/tools/soslim/prelink_info.c
new file mode 100644 (file)
index 0000000..81d5de3
--- /dev/null
@@ -0,0 +1,109 @@
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <prelink_info.h>
+#include <debug.h>
+#include <common.h>
+
+typedef struct {
+       uint32_t mmap_addr;
+       char tag[4]; /* 'P', 'R', 'E', ' ' */
+} __attribute__((packed)) prelink_info_t;
+
+static inline void set_prelink(long *prelink_addr, 
+                                                          int elf_little,
+                                                          prelink_info_t *info)
+{
+    FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %zd!\n", sizeof(prelink_info_t));
+       if (prelink_addr) {
+               if (!(elf_little ^ is_host_little())) {
+                       /* Same endianness */
+                       *prelink_addr = info->mmap_addr;
+               }
+               else {
+                       /* Different endianness */
+                       *prelink_addr = switch_endianness(info->mmap_addr);
+               }
+       }
+}
+
+int check_prelinked(const char *fname, int elf_little, long *prelink_addr)
+{
+    FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %zd!\n", sizeof(prelink_info_t));
+       int fd = open(fname, O_RDONLY);
+       FAILIF(fd < 0, "open(%s, O_RDONLY): %s (%d)!\n",
+                  fname, strerror(errno), errno);
+       off_t end = lseek(fd, 0, SEEK_END);
+#ifndef DEBUG
+       (void)end;
+#endif
+
+    int nr = sizeof(prelink_info_t);
+
+    off_t sz = lseek(fd, -nr, SEEK_CUR);
+       ASSERT((long)(end - sz) == (long)nr);
+       FAILIF(sz == (off_t)-1, 
+                  "lseek(%d, 0, SEEK_END): %s (%d)!\n", 
+                  fd, strerror(errno), errno);
+
+       prelink_info_t info;
+       ssize_t num_read = read(fd, &info, nr);
+       FAILIF(num_read < 0, 
+                  "read(%d, &info, sizeof(prelink_info_t)): %s (%d)!\n",
+                  fd, strerror(errno), errno);
+       FAILIF((size_t)num_read != sizeof(info),
+                  "read(%d, &info, sizeof(prelink_info_t)): did not read %zd bytes as "
+                  "expected (read %zd)!\n",
+                  fd, sizeof(info), (size_t)num_read);
+
+       int prelinked = 0;
+       if (!strncmp(info.tag, "PRE ", 4)) {
+               set_prelink(prelink_addr, elf_little, &info);
+               prelinked = 1;
+       }
+       FAILIF(close(fd) < 0, "close(%d): %s (%d)!\n", fd, strerror(errno), errno);
+       return prelinked;
+}
+
+void setup_prelink_info(const char *fname, int elf_little, long base)
+{
+    FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %zd!\n", sizeof(prelink_info_t));
+    int fd = open(fname, O_WRONLY);
+    FAILIF(fd < 0, 
+           "open(%s, O_WRONLY): %s (%d)\n" ,
+           fname, strerror(errno), errno);
+    prelink_info_t info;
+    off_t sz = lseek(fd, 0, SEEK_END);
+    FAILIF(sz == (off_t)-1, 
+           "lseek(%d, 0, SEEK_END): %s (%d)!\n", 
+           fd, strerror(errno), errno);
+
+    if (!(elf_little ^ is_host_little())) {
+        /* Same endianness */
+        INFO("Host and ELF file [%s] have same endianness.\n", fname);
+        info.mmap_addr = base;
+    }
+    else {
+        /* Different endianness */
+        INFO("Host and ELF file [%s] have different endianness.\n", fname);
+               info.mmap_addr = switch_endianness(base);
+    }
+    strncpy(info.tag, "PRE ", 4);
+
+    ssize_t num_written = write(fd, &info, sizeof(info));
+    FAILIF(num_written < 0, 
+           "write(%d, &info, sizeof(info)): %s (%d)\n",
+           fd, strerror(errno), errno);
+    FAILIF(sizeof(info) != (size_t)num_written,
+           "Could not write %zd bytes (wrote only %zd bytes) as expected!\n",
+           sizeof(info), (size_t)num_written);
+    FAILIF(close(fd) < 0, "close(%d): %s (%d)!\n", fd, strerror(errno), errno);
+}
+
+#endif /*SUPPORT_ANDROID_PRELINK_TAGS*/
diff --git a/build/tools/soslim/prelink_info.h b/build/tools/soslim/prelink_info.h
new file mode 100644 (file)
index 0000000..e2787cb
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef PRELINK_INFO_H
+#define PRELINK_INFO_H
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+
+int check_prelinked(const char *fname, int elf_little, long *prelink_addr);
+void setup_prelink_info(const char *fname, int elf_little, long base);
+
+#endif
+#endif/*PRELINK_INFO_H*/
diff --git a/build/tools/soslim/soslim.c b/build/tools/soslim/soslim.c
new file mode 100644 (file)
index 0000000..125e29e
--- /dev/null
@@ -0,0 +1,528 @@
+#include <stdio.h>
+//#include <common.h>
+#include <debug.h>
+#include <libelf.h>
+#include <libebl.h>
+#include <libebl_arm.h>
+#include <elf.h>
+#include <gelf.h>
+#include <string.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+#include <prelink_info.h>
+#endif
+
+#include <elfcopy.h>
+
+void clone_elf(Elf *elf, Elf *newelf,
+               const char *elf_name,
+               const char *newelf_name,
+               bool *sym_filter, int num_symbols,
+               int shady
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+               , int *prelinked,
+               int *elf_little,
+               long *prelink_addr
+#endif
+               , bool rebuild_shstrtab,
+               bool strip_debug,
+               bool dry_run)
+{
+       GElf_Ehdr ehdr_mem, *ehdr; /* store ELF header of original library */
+       size_t shstrndx; /* section-strings-section index */
+       size_t shnum; /* number of sections in the original file */
+       /* string table for section headers in new file */
+       struct Ebl_Strtab *shst = NULL;
+    int dynamic_idx = -1; /* index in shdr_info[] of .dynamic section */
+    int dynsym_idx = -1; /* index in shdr_info[] of dynamic symbol table
+                            section */
+
+    unsigned int cnt;    /* general-purpose counter */
+    /* This flag is true when at least one section is dropped or when the
+       relative order of sections has changed, so that section indices in
+       the resulting file will be different from those in the original. */
+    bool sections_dropped_or_rearranged;
+       Elf_Scn *scn; /* general-purpose section */
+       size_t idx;       /* general-purporse section index */
+
+       shdr_info_t *shdr_info = NULL;
+    unsigned int shdr_info_len = 0;
+    GElf_Phdr *phdr_info = NULL;
+
+       /* Get the information from the old file. */
+       ehdr = gelf_getehdr (elf, &ehdr_mem);
+       FAILIF_LIBELF(NULL == ehdr, gelf_getehdr);
+
+       /* Create new program header for the elf file */
+       FAILIF(gelf_newehdr (newelf, gelf_getclass (elf)) == 0 ||
+                  (ehdr->e_type != ET_REL && gelf_newphdr (newelf,
+                                                                                                       ehdr->e_phnum) == 0),
+                  "Cannot create new file: %s", elf_errmsg (-1));
+
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+    ASSERT(prelinked);
+    ASSERT(prelink_addr);
+    ASSERT(elf_little);
+    *elf_little = (ehdr->e_ident[EI_DATA] == ELFDATA2LSB);
+    *prelinked = check_prelinked(elf_name, *elf_little, prelink_addr);
+#endif
+
+    INFO("\n\nCALCULATING MODIFICATIONS\n\n");
+
+       /* Copy out the old program header: notice that if the ELF file does not
+          have a program header, this loop won't execute.
+       */
+       INFO("Copying ELF program header...\n");
+    phdr_info = (GElf_Phdr *)CALLOC(ehdr->e_phnum, sizeof(GElf_Phdr));
+       for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) {
+               INFO("\tRetrieving entry %d\n", cnt);
+               FAILIF_LIBELF(NULL == gelf_getphdr(elf, cnt, phdr_info + cnt),
+                      gelf_getphdr);
+        /* -- we update the header at the end
+        FAILIF_LIBELF(gelf_update_phdr (newelf, cnt, phdr_info + cnt) == 0,
+                      gelf_update_phdr);
+        */
+       }
+
+    /* Get the section-header strings section.  This section contains the
+          strings used to name the other sections. */
+       FAILIF_LIBELF(elf_getshstrndx(elf, &shstrndx) < 0, elf_getshstrndx);
+
+       /* Get the number of sections. */
+       FAILIF_LIBELF(elf_getshnum (elf, &shnum) < 0, elf_getshnum);
+       INFO("Original ELF file has %zd sections.\n", shnum);
+
+       /* Allocate the section-header-info buffer.  We allocate one more entry
+       for the section-strings section because we regenerate that one and
+       place it at the very end of the file.  Note that just because we create
+       an extra entry in the shdr_info array, it does not mean that we create
+       one more section the header.  We just mark the old section for removal
+       and create one as the last section.
+    */
+       INFO("Allocating section-header info structure (%zd) bytes...\n",
+                shnum*sizeof (shdr_info_t));
+    shdr_info_len = rebuild_shstrtab ? shnum + 1 : shnum;
+       shdr_info = (shdr_info_t *)CALLOC(shdr_info_len, sizeof (shdr_info_t));
+
+       /* Iterate over all the sections and initialize the internal section-info
+          array...
+       */
+       INFO("Initializing section-header info structure...\n");
+       /* Gather information about the sections in this file. */
+       scn = NULL;
+       cnt = 1;
+       while ((scn = elf_nextscn (elf, scn)) != NULL) {
+               ASSERT(elf_ndxscn(scn) == cnt);
+               shdr_info[cnt].scn = scn;
+               FAILIF_LIBELF(NULL == gelf_getshdr(scn, &shdr_info[cnt].shdr),
+                                         gelf_getshdr);
+
+               /* Get the name of the section. */
+               shdr_info[cnt].name = elf_strptr (elf, shstrndx,
+                                                                                 shdr_info[cnt].shdr.sh_name);
+
+               INFO("\tname: %s\n", shdr_info[cnt].name);
+               FAILIF(shdr_info[cnt].name == NULL,
+                          "Malformed file: section %d name is null\n",
+                          cnt);
+
+               /* Mark them as present but not yet investigated.  By "investigating"
+                  sections, we mean that we check to see if by stripping other
+                  sections, the sections under investigation will be compromised.  For
+                  example, if we are removing a section of code, then we want to make
+                  sure that the symbol table does not contain symbols that refer to
+                  this code, so we investigate the symbol table.  If we do find such
+                  symbols, we will not strip the code section.
+               */
+               shdr_info[cnt].idx = 1;
+
+               /* Remember the shdr.sh_link value.  We need to remember this value
+                  for those sections that refer to other sections.  For example,
+                  we need to remember it for relocation-entry sections, because if
+                  we modify the symbol table that a relocation-entry section is
+                  relative to, then we need to patch the relocation section.  By the
+                  time we get to deciding whether we need to patch the relocation
+                  section, we will have overwritten its header's sh_link field with
+                  a new value.
+               */
+               shdr_info[cnt].old_shdr = shdr_info[cnt].shdr;
+        INFO("\t\toriginal sh_link: %08d\n", shdr_info[cnt].old_shdr.sh_link);
+        INFO("\t\toriginal sh_addr: %lld\n", shdr_info[cnt].old_shdr.sh_addr);
+        INFO("\t\toriginal sh_offset: %lld\n",
+             shdr_info[cnt].old_shdr.sh_offset);
+        INFO("\t\toriginal sh_size: %lld\n", shdr_info[cnt].old_shdr.sh_size);
+
+        if (shdr_info[cnt].shdr.sh_type == SHT_DYNAMIC) {
+            INFO("\t\tthis is the SHT_DYNAMIC section [%s] at index %d\n",
+                 shdr_info[cnt].name,
+                 cnt);
+            dynamic_idx = cnt;
+        }
+        else if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM) {
+            INFO("\t\tthis is the SHT_DYNSYM section [%s] at index %d\n",
+                 shdr_info[cnt].name,
+                 cnt);
+            dynsym_idx = cnt;
+        }
+
+               FAILIF(shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX,
+                          "Cannot handle sh_type SHT_SYMTAB_SHNDX!\n");
+               FAILIF(shdr_info[cnt].shdr.sh_type == SHT_GROUP,
+                          "Cannot handle sh_type SHT_GROUP!\n");
+               FAILIF(shdr_info[cnt].shdr.sh_type == SHT_GNU_versym,
+                          "Cannot handle sh_type SHT_GNU_versym!\n");
+
+               /* Increment the counter. */
+               ++cnt;
+       } /* while */
+
+       /* Get the EBL handling. */
+       Ebl *ebl = ebl_openbackend (elf);
+       FAILIF_LIBELF(NULL == ebl, ebl_openbackend);
+    FAILIF_LIBELF(0 != arm_init(elf, ehdr->e_machine, ebl, sizeof(Ebl)),
+                  arm_init);
+
+    if (strip_debug) {
+
+      /* This will actually strip more than just sections.  It will strip
+         anything not essential to running the image.
+      */
+
+      INFO("Finding debug sections to strip.\n");
+
+      /* Now determine which sections can go away.  The general rule is that
+         all sections which are not used at runtime are stripped out.  But
+         there are a few exceptions:
+
+         - special sections named ".comment" and ".note" are kept
+         - OS or architecture specific sections are kept since we might not
+                know how to handle them
+         - if a section is referred to from a section which is not removed
+                in the sh_link or sh_info element it cannot be removed either
+      */
+      for (cnt = 1; cnt < shnum; ++cnt) {
+               /* Check whether the section can be removed.  */
+               if (SECTION_STRIP_P (ebl, elf, ehdr, &shdr_info[cnt].shdr,
+                                                        shdr_info[cnt].name,
+                                                        1,      /* remove .comment sections */
+                                                        1       /* remove all debug sections */) ||
+            /* The macro above is broken--check for .comment explicitly */
+            !strcmp(".comment", shdr_info[cnt].name)
+#ifdef ARM_SPECIFIC_HACKS
+            ||
+            /* We ignore this section, that's why we can remove it. */
+            !strcmp(".stack", shdr_info[cnt].name)
+#endif
+            )
+        {
+          /* For now assume this section will be removed.  */
+          INFO("Section [%s] will be stripped from image.\n",
+               shdr_info[cnt].name);
+          shdr_info[cnt].idx = 0;
+               }
+#ifdef STRIP_STATIC_SYMBOLS
+               else if (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB) {
+          /* Mark the static symbol table for removal */
+          INFO("Section [%s] (static symbol table) will be stripped from image.\n",
+               shdr_info[cnt].name);
+          shdr_info[cnt].idx = 0;
+          if (shdr_info[shdr_info[cnt].shdr.sh_link].shdr.sh_type ==
+              SHT_STRTAB)
+          {
+            /* Mark the symbol table's string table for removal. */
+            INFO("Section [%s] (static symbol-string table) will be stripped from image.\n",
+                 shdr_info[shdr_info[cnt].shdr.sh_link].name);
+            shdr_info[shdr_info[cnt].shdr.sh_link].idx = 0;
+          }
+          else {
+            ERROR("Expecting the sh_link field of a symbol table to point to"
+                  " associated symbol-strings table!  This is not mandated by"
+                  " the standard, but is a common practice and the only way "
+                  " to know for sure which strings table corresponds to which"
+                  " symbol table!\n");
+          }
+               }
+#endif
+      }
+
+      /* Mark the SHT_NULL section as handled. */
+      shdr_info[0].idx = 2;
+
+      /* Handle exceptions: section groups and cross-references.  We might have
+         to repeat this a few times since the resetting of the flag might
+         propagate.
+      */
+      int exceptions_pass = 0;
+      bool changes;
+      do {
+        changes = false;
+               INFO("\nHandling exceptions, pass %d\n\n", exceptions_pass++);
+               for (cnt = 1; cnt < shnum; ++cnt) {
+          if (shdr_info[cnt].idx == 0) {
+            /* If a relocation section is marked as being removed but the
+               section it is relocating is not, then do not remove the
+               relocation section.
+            */
+            if ((shdr_info[cnt].shdr.sh_type == SHT_REL
+                 || shdr_info[cnt].shdr.sh_type == SHT_RELA)
+                && shdr_info[shdr_info[cnt].shdr.sh_info].idx != 0) {
+              PRINT("\tSection [%s] will not be removed because the "
+                    "section it is relocating (%s) stays.\n",
+                    shdr_info[cnt].name,
+                    shdr_info[shdr_info[cnt].shdr.sh_info].name);
+            }
+          }
+          if (shdr_info[cnt].idx == 1) {
+            INFO("Processing section [%s]...\n", shdr_info[cnt].name);
+
+            /* The content of symbol tables we don't remove must not
+               reference any section which we do remove.  Otherwise
+               we cannot remove the referred section.
+            */
+            if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM ||
+                shdr_info[cnt].shdr.sh_type == SHT_SYMTAB)
+            {
+              Elf_Data *symdata;
+              size_t elsize;
+
+              INFO("\tSection [%s] is a symbol table that's not being"
+                   " removed.\n\tChecking to make sure that no symbols"
+                   " refer to sections that are being removed.\n",
+                   shdr_info[cnt].name);
+
+              /* Make sure the data is loaded.  */
+              symdata = elf_getdata (shdr_info[cnt].scn, NULL);
+              FAILIF_LIBELF(NULL == symdata, elf_getdata);
+
+              /* Go through all symbols and make sure the section they
+                 reference is not removed.  */
+              elsize = gelf_fsize (elf, ELF_T_SYM, 1, ehdr->e_version);
+
+              /* Check the length of the dynamic-symbol filter. */
+              FAILIF(sym_filter != NULL &&
+                     (size_t)num_symbols != symdata->d_size / elsize,
+                     "Length of dynsym filter (%d) must equal the number"
+                     " of dynamic symbols (%zd)!\n",
+                     num_symbols,
+                     symdata->d_size / elsize);
+
+              size_t inner;
+              for (inner = 0;
+                   inner < symdata->d_size / elsize;
+                   ++inner)
+              {
+                GElf_Sym sym_mem;
+                GElf_Sym *sym;
+                size_t scnidx;
+
+                sym = gelf_getsymshndx (symdata, NULL,
+                                        inner, &sym_mem, NULL);
+                FAILIF_LIBELF(sym == NULL, gelf_getsymshndx);
+
+                scnidx = sym->st_shndx;
+                FAILIF(scnidx == SHN_XINDEX,
+                       "Can't handle SHN_XINDEX!\n");
+                if (scnidx == SHN_UNDEF ||
+                    scnidx >= shnum ||
+                    (scnidx >= SHN_LORESERVE &&
+                     scnidx <= SHN_HIRESERVE) ||
+                    GELF_ST_TYPE (sym->st_info) == STT_SECTION)
+                {
+                  continue;
+                }
+
+                /* If the symbol is going to be thrown and it is a
+                   global or weak symbol that is defined (not imported),
+                   then continue.  Since the symbol is going away, we
+                   do not care  whether it refers to a section that is
+                   also going away.
+                */
+                if (sym_filter && !sym_filter[inner])
+                {
+                  bool global_or_weak =
+                      ELF32_ST_BIND(sym->st_info) == STB_GLOBAL ||
+                      ELF32_ST_BIND(sym->st_info) == STB_WEAK;
+                  if (!global_or_weak && sym->st_shndx != SHN_UNDEF)
+                    continue;
+                }
+
+                /* -- far too much output
+                   INFO("\t\t\tSymbol [%s] (%d)\n",
+                   elf_strptr(elf,
+                   shdr_info[cnt].shdr.sh_link,
+                   sym->st_name),
+                   shdr_info[cnt].shdr.sh_info);
+                */
+
+                if (shdr_info[scnidx].idx == 0)
+                {
+                  PRINT("\t\t\tSymbol [%s] refers to section [%s], "
+                        "which is being removed.  Will keep that "
+                        "section.\n",
+                        elf_strptr(elf,
+                                   shdr_info[cnt].shdr.sh_link,
+                                   sym->st_name),
+                        shdr_info[scnidx].name);
+                  /* Mark this section as used.  */
+                  shdr_info[scnidx].idx = 1;
+                  changes |= scnidx < cnt;
+                }
+              } /* for each symbol */
+            } /* section type is SHT_DYNSYM or SHT_SYMTAB */
+            /* Cross referencing happens:
+                          - for the cases the ELF specification says.  That are
+                          + SHT_DYNAMIC in sh_link to string table
+                          + SHT_HASH in sh_link to symbol table
+                          + SHT_REL and SHT_RELA in sh_link to symbol table
+                          + SHT_SYMTAB and SHT_DYNSYM in sh_link to string table
+                          + SHT_GROUP in sh_link to symbol table
+                          + SHT_SYMTAB_SHNDX in sh_link to symbol table
+                          Other (OS or architecture-specific) sections might as
+                          well use this field so we process it unconditionally.
+                          - references inside section groups
+                          - specially marked references in sh_info if the SHF_INFO_LINK
+                          flag is set
+            */
+
+            if (shdr_info[shdr_info[cnt].shdr.sh_link].idx == 0) {
+              shdr_info[shdr_info[cnt].shdr.sh_link].idx = 1;
+              changes |= shdr_info[cnt].shdr.sh_link < cnt;
+            }
+
+            /* Handle references through sh_info.  */
+            if (SH_INFO_LINK_P (&shdr_info[cnt].shdr) &&
+                shdr_info[shdr_info[cnt].shdr.sh_info].idx == 0) {
+              PRINT("\tSection [%s] links to section [%s], which was "
+                    "marked for removal--it will not be removed.\n",
+                    shdr_info[cnt].name,
+                    shdr_info[shdr_info[cnt].shdr.sh_info].name);
+
+              shdr_info[shdr_info[cnt].shdr.sh_info].idx = 1;
+              changes |= shdr_info[cnt].shdr.sh_info < cnt;
+            }
+
+            /* Mark the section as investigated.  */
+            shdr_info[cnt].idx = 2;
+          } /* if (shdr_info[cnt].idx == 1) */
+               } /* for (cnt = 1; cnt < shnum; ++cnt) */
+      } while (changes);
+    }
+    else {
+      INFO("Not stripping sections.\n");
+      /* Mark the SHT_NULL section as handled. */
+      shdr_info[0].idx = 2;
+    }
+
+       /* Mark the section header string table as unused, we will create
+          a new one as the very last section in the new ELF file.
+       */
+       shdr_info[shstrndx].idx = rebuild_shstrtab ? 0 : 2;
+
+       /* We need a string table for the section headers. */
+       FAILIF_LIBELF((shst = ebl_strtabinit (1 /* null-terminated */)) == NULL,
+                                 ebl_strtabinit);
+
+       /* Assign new section numbers. */
+       INFO("Creating new sections...\n");
+       //shdr_info[0].idx = 0;
+       for (cnt = idx = 1; cnt < shnum; ++cnt) {
+               if (shdr_info[cnt].idx > 0) {
+                       shdr_info[cnt].idx = idx++;
+
+                       /* Create a new section. */
+                       FAILIF_LIBELF((shdr_info[cnt].newscn =
+                                                  elf_newscn(newelf)) == NULL, elf_newscn);
+                       ASSERT(elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx);
+
+                       /* Add this name to the section header string table. */
+                       shdr_info[cnt].se = ebl_strtabadd (shst, shdr_info[cnt].name, 0);
+
+                       INFO("\tsection [%s]  (old offset %lld, old size %lld) will have index %d "
+                                "(was %zd).\n",
+                                shdr_info[cnt].name,
+                                shdr_info[cnt].old_shdr.sh_offset,
+                                shdr_info[cnt].old_shdr.sh_size,
+                                shdr_info[cnt].idx,
+                                elf_ndxscn(shdr_info[cnt].scn));
+               } else {
+                       INFO("\tIgnoring section [%s] (offset %lld, size %lld, index %zd), "
+                                "it will be discarded.\n",
+                                shdr_info[cnt].name,
+                                shdr_info[cnt].shdr.sh_offset,
+                                shdr_info[cnt].shdr.sh_size,
+                                elf_ndxscn(shdr_info[cnt].scn));
+               }
+       } /* for */
+
+    sections_dropped_or_rearranged = idx != cnt;
+
+    Elf_Data *shstrtab_data = NULL;
+
+#if 0
+    /* Fail if sections are being dropped or rearranged (except for moving shstrtab) or the
+       symbol filter is not empty, AND the file is an executable.
+    */
+    FAILIF(((idx != cnt && !(cnt - idx == 1 && rebuild_shstrtab)) || sym_filter != NULL) &&
+           ehdr->e_type != ET_DYN,
+           "You may not rearrange sections or strip symbols on an executable file!\n");
+#endif
+
+    INFO("\n\nADJUSTING ELF FILE\n\n");
+
+    adjust_elf(elf, elf_name,
+               newelf, newelf_name,
+               ebl,
+               ehdr, /* store ELF header of original library */
+               sym_filter, num_symbols,
+               shdr_info, shdr_info_len,
+               phdr_info,
+               idx, /* highest_scn_num */
+               shnum,
+               shstrndx,
+               shst,
+               sections_dropped_or_rearranged,
+               dynamic_idx, /* index in shdr_info[] of .dynamic section */
+               dynsym_idx, /* index in shdr_info[] of dynamic symbol table */
+               shady,
+               &shstrtab_data,
+               ehdr->e_type == ET_DYN, /* adjust section ofsets only when the file is a shared library */
+               rebuild_shstrtab);
+
+    /* We have everything from the old file. */
+       FAILIF_LIBELF(elf_cntl(elf, ELF_C_FDDONE) != 0, elf_cntl);
+
+       /* The ELF library better follows our layout when this is not a
+          relocatable object file. */
+       elf_flagelf (newelf,
+                                ELF_C_SET,
+                                (ehdr->e_type != ET_REL ? ELF_F_LAYOUT : 0));
+
+       /* Finally write the file. */
+    FAILIF_LIBELF(!dry_run && elf_update(newelf, ELF_C_WRITE) == -1, elf_update);
+
+       if (shdr_info != NULL) {
+               /* For some sections we might have created an table to map symbol
+           table indices. */
+       for (cnt = 1; cnt < shdr_info_len; ++cnt) {
+            FREEIF(shdr_info[cnt].newsymidx);
+            FREEIF(shdr_info[cnt].symse);
+            if(shdr_info[cnt].dynsymst != NULL)
+                ebl_strtabfree (shdr_info[cnt].dynsymst);
+        }
+               /* Free the memory. */
+               FREE (shdr_info);
+       }
+    FREEIF(phdr_info);
+
+    ebl_closebackend(ebl);
+
+       /* Free other resources. */
+       if (shst != NULL) ebl_strtabfree (shst);
+    if (shstrtab_data != NULL)
+        FREEIF(shstrtab_data->d_buf);
+}
diff --git a/build/tools/soslim/soslim.h b/build/tools/soslim/soslim.h
new file mode 100644 (file)
index 0000000..dfcb085
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef ELFCOPY_H
+#define ELFCOPY_H
+
+#include <libelf.h>
+#include <libebl.h>
+#include <elf.h>
+#include <gelf.h>
+
+/*
+symbol_filter:
+       On input: symbol_filter[i] indicates whether to keep a symbol (1) or to
+                 remove it from the symbol table.
+    On output: symbol_filter[i] indicates whether a symbol was removed (0) or
+                  kept (1) in the symbol table.
+*/
+
+void clone_elf(Elf *elf, Elf *newelf,
+                          const char *elf_name,
+                          const char *newelf_name,
+                          bool *symbol_filter,
+                          int num_symbols,
+               int shady
+#ifdef SUPPORT_ANDROID_PRELINK_TAGS
+                          , int *prelinked,
+                          int *elf_little,
+                          long *prelink_addr
+#endif
+               , bool rebuild_shstrtab,
+               bool strip_debug,
+               bool dry_run);
+
+#endif/*ELFCOPY_H*/
diff --git a/build/tools/soslim/symfilter.c b/build/tools/soslim/symfilter.c
new file mode 100644 (file)
index 0000000..b59e68a
--- /dev/null
@@ -0,0 +1,246 @@
+#include <debug.h>
+#include <common.h>
+#include <symfilter.h>
+#include <hash.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <libelf.h>
+#include <gelf.h>
+#include <ctype.h>
+
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+static int match_hash_table_section(Elf *elf, Elf_Scn *sect, void *data);
+static int match_dynsym_section(Elf *elf, Elf_Scn *sect, void *data);
+
+void build_symfilter(const char *name, Elf *elf, symfilter_t *filter, 
+                     off_t fsize)
+{
+    char *line = NULL;
+    symfilter_list_t *symbol;
+
+    FAILIF(NULL == name,
+           "You must provide a list of symbols to filter on!\n");
+
+    filter->num_symbols = 0;
+    filter->total_name_length = 0;
+
+    /* Open the file. */
+    INFO("Opening symbol-filter file %s...\n", name);
+    filter->fd = open(name, O_RDONLY);
+    FAILIF(filter->fd < 0, "open(%s): %s (%d)\n",
+           name, 
+           strerror(errno),
+           errno);
+
+    INFO("Symbol-filter file %s is %zd bytes long...\n",
+         name,
+         (size_t)fsize);
+    filter->fsize = fsize;
+
+    /* mmap the symbols file */
+    filter->mmap = mmap(NULL, fsize, 
+                        PROT_READ | PROT_WRITE, MAP_PRIVATE, 
+                        filter->fd, 0);
+    FAILIF(MAP_FAILED == filter->mmap, 
+           "mmap(NULL, %zd, PROT_READ, MAP_PRIVATE, %d, 0): %s (%d)\n",
+           (size_t)fsize,
+           filter->fd,
+           strerror(errno),
+           errno);
+    INFO("Memory-mapped symbol-filter file at %p\n", filter->mmap);
+
+    /* Make sure that the ELF file has a hash table.  We will use the hash 
+       table to look up symbols quickly.  If the library does not have a hash-
+       table section, we can still do a linear scan, but the code for that is
+       not written, as practically every shared library has a hash table.
+    */
+
+    filter->symtab.sect = NULL;
+    map_over_sections(elf, match_dynsym_section, filter);
+    FAILIF(NULL == filter->symtab.sect, 
+           "There is no dynamic-symbol table in this library.\n");
+    filter->hash.sect = NULL;
+    map_over_sections(elf, match_hash_table_section, filter);
+    FAILIF(NULL == filter->hash.sect, 
+           "There is no hash table in this library.\n");
+    INFO("Hash table size 0x%lx, data size 0x%lx.\n",
+         (unsigned long)filter->hash.hdr->sh_size,
+         (unsigned long)filter->hash.data->d_size);
+
+    INFO("Hash table file offset: 0x%x\n", filter->hash.hdr->sh_offset);
+
+    GElf_Ehdr *ehdr, ehdr_mem;
+    ehdr = gelf_getehdr(elf, &ehdr_mem);
+    size_t symsize = gelf_fsize (elf, ELF_T_SYM, 1, ehdr->e_version);
+    ASSERT(symsize);
+    filter->num_symbols_to_keep = filter->symtab.data->d_size / symsize;
+    filter->symbols_to_keep = (bool *)CALLOC(filter->num_symbols_to_keep, 
+                                             sizeof(bool));
+
+    /* Build the symbol-name chain. */
+    INFO("Building symbol list...\n");
+    
+    line = (char *)filter->mmap;
+
+    filter->symbols = NULL;
+#define NOT_DONE ((off_t)(line - (char *)filter->mmap) < fsize)
+    do {
+        char *name = line;
+
+        /* Advance to the next line.  We seek out spaces or new lines.  At the
+           first space or newline character we find, we place a '\0', and 
+           continue till we've consumed the line.  For new lines, we scan both
+           '\r' and '\n'.  For spaces, we look for ' ', '\t', and '\f'
+        */
+
+        while (NOT_DONE && !isspace(*line)) line++;
+        if (likely(NOT_DONE)) {
+            *line++ = '\0';
+            if (line - name > 1) {
+                /* Add the entry to the symbol-filter list */
+                symbol = (symfilter_list_t *)MALLOC(sizeof(symfilter_list_t));
+                symbol->next = filter->symbols;
+                symbol->name = name;
+                filter->symbols = symbol;
+
+#if 0 
+                /* SLOW!  For debugging only! */
+                {
+                    size_t idx;
+                    size_t elsize = gelf_fsize(elf, ELF_T_SYM, 1, 
+                                               ehdr->e_version);
+                    symbol->index = SHN_UNDEF;
+                    for (idx = 0; idx < filter->symtab.data->d_size / elsize;
+                         idx++) {
+                        GElf_Sym sym_mem;
+                        GElf_Sym *sym;
+                        const char *symname;
+                        sym = gelf_getsymshndx (filter->symtab.data, NULL, 
+                                                idx, &sym_mem, NULL);
+                        ASSERT(sym);
+
+                        symname = elf_strptr(elf, 
+                                             filter->symtab.hdr->sh_link,
+                                             sym->st_name);
+                        if(!strcmp(symname, symbol->name)) {
+                            symbol->index = idx;
+                            break;
+                        }
+                    }
+                }
+#else
+                /* Look up the symbol in the ELF file and associate it with the
+                   entry in the filter. */
+                symbol->index = hash_lookup(elf,
+                                            &filter->hash,
+                                            &filter->symtab,
+                                            symbol->name,
+                                            &symbol->symbol);
+#endif                                            
+                symbol->len = line - name - 1;
+                ASSERT(symbol->len == strlen(symbol->name));
+
+                /* If we didn't find the symbol, then it's not in the library. 
+                 */
+
+                if(STN_UNDEF == symbol->index) {
+                    PRINT("%s: symbol was not found!\n", symbol->name);
+                }
+                else {
+                    /* If we found the symbol but it's an undefined symbol, then
+                       it's not in the library as well. */
+                    GElf_Sym sym_mem;
+                    GElf_Sym *sym;
+                    sym = gelf_getsymshndx (filter->symtab.data, NULL, 
+                                            symbol->index, &sym_mem, NULL);
+                    FAILIF_LIBELF(NULL == sym, gelf_getsymshndx);
+                    /* Make sure the hash lookup worked. */
+                    ASSERT(!strcmp(elf_strptr(elf, 
+                                              filter->symtab.hdr->sh_link,
+                                              sym->st_name),
+                                   symbol->name));
+                    if (sym->st_shndx == SHN_UNDEF) {
+                        PRINT("%s: symbol was not found (undefined)!\n", symbol->name);
+                    }
+                    else {
+                        filter->num_symbols++;
+                        /* Total count includes null terminators */
+                        filter->total_name_length += symbol->len + 1; 
+
+                        /* Set the flag in the symbols_to_keep[] array.  This indicates
+                           to function copy_elf() that we want to keep the symbol.
+                        */
+                        filter->symbols_to_keep[symbol->index] = true;
+                        INFO("FILTER-SYMBOL: [%s] [%d bytes]\n", 
+                             symbol->name, 
+                             symbol->len);
+                    }
+                }
+            }
+        }
+    } while (NOT_DONE);
+#undef NOT_DONE
+}
+
+void destroy_symfilter(symfilter_t *filter)
+{
+    symfilter_list_t *old;
+    INFO("Destroying symbol list...\n");
+    while ((old = filter->symbols)) {
+        filter->symbols = old->next;
+        FREE(old);
+    }
+    munmap(filter->mmap, filter->fsize);
+    close(filter->fd);
+}
+
+static int match_hash_table_section(Elf *elf, Elf_Scn *sect, void *data)
+{
+    (void)elf; // unused argument
+
+    symfilter_t *filter = (symfilter_t *)data;
+    Elf32_Shdr *shdr;
+
+    ASSERT(filter);
+    ASSERT(sect);
+    shdr = elf32_getshdr(sect);
+
+    /* The section must be marked both as a SHT_HASH, and it's sh_link field 
+       must contain the index of our symbol table (per ELF-file spec).
+    */
+    if (shdr->sh_type == SHT_HASH)
+    {
+        FAILIF(filter->hash.sect != NULL, 
+               "There is more than one hash table!\n");
+        get_section_info(sect, &filter->hash);
+    }
+
+    return 0; /* keep looking */
+}
+
+static int match_dynsym_section(Elf *elf, Elf_Scn *sect, void *data)
+{
+    (void)elf; // unused argument
+
+    symfilter_t *filter = (symfilter_t *)data;
+    Elf32_Shdr *shdr;
+
+    ASSERT(filter);
+    ASSERT(sect);
+    shdr = elf32_getshdr(sect);
+
+    if (shdr->sh_type == SHT_DYNSYM)
+    {
+        FAILIF(filter->symtab.sect != NULL, 
+               "There is more than one dynamic symbol table!\n");
+        get_section_info(sect, &filter->symtab);
+    }
+
+    return 0; /* keep looking */
+}
diff --git a/build/tools/soslim/symfilter.h b/build/tools/soslim/symfilter.h
new file mode 100644 (file)
index 0000000..f73fd50
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef SYMFILTER_H
+#define SYMFILTER_H
+
+/* This file describes the interface for parsing the list of symbols. Currently,
+   this is just a text file with each symbol on a separate line.  We build an
+   in-memory linked list of symbols out of this image.
+*/
+
+#include <stdio.h>
+#include <libelf.h>
+#include <gelf.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <libebl.h> /* defines bool */
+
+typedef struct symfilter_list_t symfilter_list_t;
+struct symfilter_list_t {
+    symfilter_list_t *next;
+    const char *name;
+    unsigned int len; /* strlen(name) */
+    Elf32_Word index;
+    GElf_Sym symbol;
+};
+
+typedef struct symfilter_t {
+
+    int fd; /* symbol-filter-file descriptor */
+    off_t fsize; /* size of file */
+    void *mmap; /* symbol-fiter-file memory mapping */
+
+    section_info_t symtab;
+    section_info_t hash;
+    symfilter_list_t *symbols;
+
+    /* The total number of symbols in the symfilter. */
+    unsigned int num_symbols;
+    /* The total number of bytes occupied by the names of the symbols, including
+       the terminating null characters.
+    */
+    unsigned int total_name_length;
+
+    bool *symbols_to_keep;
+    /* must be the same as the number of symbols in the dynamic table! */
+    int num_symbols_to_keep;
+} symfilter_t;
+
+void build_symfilter(const char *name, Elf *elf, symfilter_t *filter, off_t);
+void destroy_symfilter(symfilter_t *);
+
+#endif/*SYMFILTER_H*/
diff --git a/build/tools/warn.py b/build/tools/warn.py
new file mode 100644 (file)
index 0000000..8097123
--- /dev/null
@@ -0,0 +1,563 @@
+#!/usr/bin/env python
+# This file uses the following encoding: utf-8
+
+import sys
+import re
+
+if len(sys.argv) == 1:
+    print 'usage: ' + sys.argv[0] + ' <build.log>'
+    sys.exit()
+
+# if you add another level, don't forget to give it a color below
+class severity:
+    UNKNOWN=0
+    SKIP=100
+    FIXMENOW=1
+    HIGH=2
+    MEDIUM=3
+    LOW=4
+    HARMLESS=5
+
+def colorforseverity(sev):
+    if sev == severity.FIXMENOW:
+        return 'fuchsia'
+    if sev == severity.HIGH:
+        return 'red'
+    if sev == severity.MEDIUM:
+        return 'orange'
+    if sev == severity.LOW:
+        return 'yellow'
+    if sev == severity.HARMLESS:
+        return 'limegreen'
+    if sev == severity.UNKNOWN:
+        return 'blue'
+    return 'grey'
+
+warnpatterns = [
+    { 'category':'make',    'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'make: overriding commands/ignoring old commands',
+        'patterns':[r".*: warning: overriding commands for target .+",
+                    r".*: warning: ignoring old commands for target .+"] },
+    { 'category':'C/C++',   'severity':severity.HIGH,     'members':[], 'option':'-Wimplicit-function-declaration',
+        'description':'Implicit function declaration',
+        'patterns':[r".*: warning: implicit declaration of function .+"] },
+    { 'category':'C/C++',   'severity':severity.SKIP,     'members':[], 'option':'',
+        'description':'',
+        'patterns':[r".*: warning: conflicting types for '.+'"] },
+    { 'category':'C/C++',   'severity':severity.HIGH,     'members':[], 'option':'-Wtype-limits',
+        'description':'Expression always evaluates to true or false',
+        'patterns':[r".*: warning: comparison is always false due to limited range of data type",
+                    r".*: warning: comparison of unsigned expression >= 0 is always true",
+                    r".*: warning: comparison of unsigned expression < 0 is always false"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Incompatible pointer types',
+        'patterns':[r".*: warning: assignment from incompatible pointer type",
+                    r".*: warning: return from incompatible pointer type",
+                    r".*: warning: passing argument [0-9]+ of '.*' from incompatible pointer type",
+                    r".*: warning: initialization from incompatible pointer type"] },
+    { 'category':'C/C++',   'severity':severity.HIGH,     'members':[], 'option':'-fno-builtin',
+        'description':'Incompatible declaration of built in function',
+        'patterns':[r".*: warning: incompatible implicit declaration of built-in function .+"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wunused-parameter',
+        'description':'Unused parameter',
+        'patterns':[r".*: warning: unused parameter '.*'"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wunused',
+        'description':'Unused function, variable or label',
+        'patterns':[r".*: warning: '.+' defined but not used",
+                    r".*: warning: unused variable '.+'"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wunused-value',
+        'description':'Statement with no effect',
+        'patterns':[r".*: warning: statement with no effect"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wmissing-field-initializers',
+        'description':'Missing initializer',
+        'patterns':[r".*: warning: missing initializer"] },
+    { 'category':'cont.',   'severity':severity.SKIP,     'members':[], 'option':'',
+        'description':'',
+        'patterns':[r".*: warning: \(near initialization for '.+'\)"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wformat',
+        'description':'Format string does not match arguments',
+        'patterns':[r".*: warning: format '.+' expects type '.+', but argument [0-9]+ has type '.+'"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wformat-extra-args',
+        'description':'Too many arguments for format string',
+        'patterns':[r".*: warning: too many arguments for format"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wsign-compare',
+        'description':'Comparison between signed and unsigned',
+        'patterns':[r".*: warning: comparison between signed and unsigned",
+                    r".*: warning: comparison of promoted \~unsigned with unsigned",
+                    r".*: warning: signed and unsigned type in conditional expression"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Comparison between enum and non-enum',
+        'patterns':[r".*: warning: enumeral and non-enumeral type in conditional expression"] },
+    { 'category':'libpng',  'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'libpng: zero area',
+        'patterns':[r".*libpng warning: Ignoring attempt to set cHRM RGB triangle with zero area"] },
+    { 'category':'aapt',    'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'aapt: no comment for public symbol',
+        'patterns':[r".*: warning: No comment for public symbol .+"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wmissing-braces',
+        'description':'Missing braces around initializer',
+        'patterns':[r".*: warning: missing braces around initializer.*"] },
+    { 'category':'C/C++',   'severity':severity.HARMLESS, 'members':[], 'option':'',
+        'description':'No newline at end of file',
+        'patterns':[r".*: warning: no newline at end of file"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wcast-qual',
+        'description':'Qualifier discarded',
+        'patterns':[r".*: warning: passing argument [0-9]+ of '.+' discards qualifiers from pointer target type",
+                    r".*: warning: assignment discards qualifiers from pointer target type",
+                    r".*: warning: return discards qualifiers from pointer target type"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wattributes',
+        'description':'Attribute ignored',
+        'patterns':[r".*: warning: '_*packed_*' attribute ignored"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wattributes',
+        'description':'Visibility mismatch',
+        'patterns':[r".*: warning: '.+' declared with greater visibility than the type of its field '.+'"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Shift count greater than width of type',
+        'patterns':[r".*: warning: (left|right) shift count >= width of type"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'extern &lt;foo&gt; is initialized',
+        'patterns':[r".*: warning: '.+' initialized and declared 'extern'"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wold-style-declaration',
+        'description':'Old style declaration',
+        'patterns':[r".*: warning: 'static' is not at beginning of declaration"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wuninitialized',
+        'description':'Variable may be used uninitialized',
+        'patterns':[r".*: warning: '.+' may be used uninitialized in this function"] },
+    { 'category':'C/C++',   'severity':severity.HIGH,     'members':[], 'option':'-Wuninitialized',
+        'description':'Variable is used uninitialized',
+        'patterns':[r".*: warning: '.+' is used uninitialized in this function"] },
+    { 'category':'ld',      'severity':severity.MEDIUM,   'members':[], 'option':'-fshort-enums',
+        'description':'ld: possible enum size mismatch',
+        'patterns':[r".*: warning: .* uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wpointer-sign',
+        'description':'Pointer targets differ in signedness',
+        'patterns':[r".*: warning: pointer targets in initialization differ in signedness",
+                    r".*: warning: pointer targets in assignment differ in signedness",
+                    r".*: warning: pointer targets in return differ in signedness",
+                    r".*: warning: pointer targets in passing argument [0-9]+ of '.+' differ in signedness"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wstrict-overflow',
+        'description':'Assuming overflow does not occur',
+        'patterns':[r".*: warning: assuming signed overflow does not occur when assuming that .* is always (true|false)"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wempty-body',
+        'description':'Suggest adding braces around empty body',
+        'patterns':[r".*: warning: suggest braces around empty body in an 'if' statement",
+                    r".*: warning: empty body in an if-statement",
+                    r".*: warning: suggest braces around empty body in an 'else' statement",
+                    r".*: warning: empty body in an else-statement"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wparentheses',
+        'description':'Suggest adding parentheses',
+        'patterns':[r".*: warning: suggest explicit braces to avoid ambiguous 'else'",
+                    r".*: warning: suggest parentheses around arithmetic in operand of '.+'",
+                    r".*: warning: suggest parentheses around comparison in operand of '.+'",
+                    r".*: warning: suggest parentheses around '.+?' .+ '.+?'",
+                    r".*: warning: suggest parentheses around assignment used as truth value"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Static variable used in non-static inline function',
+        'patterns':[r".*: warning: '.+' is static but used in inline function '.+' which is not static"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wimplicit int',
+        'description':'No type or storage class (will default to int)',
+        'patterns':[r".*: warning: data definition has no type or storage class"] },
+    { 'category':'cont.',   'severity':severity.SKIP,     'members':[], 'option':'',
+        'description':'',
+        'patterns':[r".*: warning: type defaults to 'int' in declaration of '.+'"] },
+    { 'category':'cont.',   'severity':severity.SKIP,     'members':[], 'option':'',
+        'description':'',
+        'patterns':[r".*: warning: parameter names \(without types\) in function declaration"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wstrict-aliasing',
+        'description':'Dereferencing &lt;foo&gt; breaks strict aliasing rules',
+        'patterns':[r".*: warning: dereferencing .* break strict-aliasing rules"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wpointer-to-int-cast',
+        'description':'Cast from pointer to integer of different size',
+        'patterns':[r".*: warning: cast from pointer to integer of different size"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wint-to-pointer-cast',
+        'description':'Cast to pointer from integer of different size',
+        'patterns':[r".*: warning: cast to pointer from integer of different size"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Symbol redefined',
+        'patterns':[r".*: warning: "".+"" redefined"] },
+    { 'category':'cont.',   'severity':severity.SKIP,     'members':[], 'option':'',
+        'description':'',
+        'patterns':[r".*: warning: this is the location of the previous definition"] },
+    { 'category':'ld',      'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'ld: type and size of dynamic symbol are not defined',
+        'patterns':[r".*: warning: type and size of dynamic symbol `.+' are not defined"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Pointer from integer without cast',
+        'patterns':[r".*: warning: assignment makes pointer from integer without a cast"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Pointer from integer without cast',
+        'patterns':[r".*: warning: passing argument [0-9]+ of '.+' makes pointer from integer without a cast"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Integer from pointer without cast',
+        'patterns':[r".*: warning: assignment makes integer from pointer without a cast"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Integer from pointer without cast',
+        'patterns':[r".*: warning: passing argument [0-9]+ of '.+' makes integer from pointer without a cast"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Integer from pointer without cast',
+        'patterns':[r".*: warning: return makes integer from pointer without a cast"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wunknown-pragmas',
+        'description':'Ignoring pragma',
+        'patterns':[r".*: warning: ignoring #pragma .+"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wclobbered',
+        'description':'Variable might be clobbered by longjmp or vfork',
+        'patterns':[r".*: warning: variable '.+' might be clobbered by 'longjmp' or 'vfork'"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wclobbered',
+        'description':'Argument might be clobbered by longjmp or vfork',
+        'patterns':[r".*: warning: argument '.+' might be clobbered by 'longjmp' or 'vfork'"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wredundant-decls',
+        'description':'Redundant declaration',
+        'patterns':[r".*: warning: redundant redeclaration of '.+'"] },
+    { 'category':'cont.',   'severity':severity.SKIP,     'members':[], 'option':'',
+        'description':'',
+        'patterns':[r".*: warning: previous declaration of '.+' was here"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wswitch-enum',
+        'description':'Enum value not handled in switch',
+        'patterns':[r".*: warning: enumeration value '.+' not handled in switch"] },
+    { 'category':'java',    'severity':severity.MEDIUM,   'members':[], 'option':'-encoding',
+        'description':'Java: Non-ascii characters used, but ascii encoding specified',
+        'patterns':[r".*: warning: unmappable character for encoding ascii"] },
+    { 'category':'java',    'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Java: Non-varargs call of varargs method with inexact argument type for last parameter',
+        'patterns':[r".*: warning: non-varargs call of varargs method with inexact argument type for last parameter"] },
+    { 'category':'aapt',    'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'aapt: No default translation',
+        'patterns':[r".*: warning: string '.+' has no default translation in .*"] },
+    { 'category':'aapt',    'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'aapt: Missing default or required localization',
+        'patterns':[r".*: warning: \*\*\*\* string '.+' has no default or required localization for '.+' in .+"] },
+    { 'category':'aapt',    'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'aapt: String marked untranslatable, but translation exists',
+        'patterns':[r".*: warning: string '.+' in .* marked untranslatable but exists in locale '??_??'"] },
+    { 'category':'aapt',    'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'aapt: empty span in string',
+        'patterns':[r".*: warning: empty '.+' span found in text '.+"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Taking address of temporary',
+        'patterns':[r".*: warning: taking address of temporary"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Possible broken line continuation',
+        'patterns':[r".*: warning: backslash and newline separated by space"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Warray-bounds',
+        'description':'Array subscript out of bounds',
+        'patterns':[r".*: warning: array subscript is above array bounds",
+                    r".*: warning: array subscript is below array bounds"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Decimal constant is unsigned only in ISO C90',
+        'patterns':[r".*: warning: this decimal constant is unsigned only in ISO C90"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wmain',
+        'description':'main is usually a function',
+        'patterns':[r".*: warning: 'main' is usually a function"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Typedef ignored',
+        'patterns':[r".*: warning: 'typedef' was ignored in this declaration"] },
+    { 'category':'C/C++',   'severity':severity.HIGH,     'members':[], 'option':'-Waddress',
+        'description':'Address always evaluates to true',
+        'patterns':[r".*: warning: the address of '.+' will always evaluate as 'true'"] },
+    { 'category':'C/C++',   'severity':severity.FIXMENOW, 'members':[], 'option':'',
+        'description':'Freeing a non-heap object',
+        'patterns':[r".*: warning: attempt to free a non-heap object '.+'"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wchar-subscripts',
+        'description':'Array subscript has type char',
+        'patterns':[r".*: warning: array subscript has type 'char'"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Constant too large for type',
+        'patterns':[r".*: warning: integer constant is too large for '.+' type"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Woverflow',
+        'description':'Constant too large for type, truncated',
+        'patterns':[r".*: warning: large integer implicitly truncated to unsigned type"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Woverflow',
+        'description':'Overflow in implicit constant conversion',
+        'patterns':[r".*: warning: overflow in implicit constant conversion"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Declaration does not declare anything',
+        'patterns':[r".*: warning: declaration 'class .+' does not declare anything"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wreorder',
+        'description':'Initialization order will be different',
+        'patterns':[r".*: warning: '.+' will be initialized after"] },
+    { 'category':'cont.',   'severity':severity.SKIP,     'members':[], 'option':'',
+        'description':'',
+        'patterns':[r".*: warning:   '.+'"] },
+    { 'category':'cont.',   'severity':severity.SKIP,     'members':[], 'option':'',
+        'description':'',
+        'patterns':[r".*: warning:   base '.+'"] },
+    { 'category':'cont.',   'severity':severity.SKIP,     'members':[], 'option':'',
+        'description':'',
+        'patterns':[r".*: warning:   when initialized here"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wmissing-parameter-type',
+        'description':'Parameter type not specified',
+        'patterns':[r".*: warning: type of '.+' defaults to 'int'"] },
+    { 'category':'gcc',     'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Invalid option for C file',
+        'patterns':[r".*: warning: command line option "".+"" is valid for C\+\+\/ObjC\+\+ but not for C"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'User warning',
+        'patterns':[r".*: warning: #warning "".+"""] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wextra',
+        'description':'Dereferencing void*',
+        'patterns':[r".*: warning: dereferencing 'void \*' pointer"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wextra',
+        'description':'Comparison of pointer to zero',
+        'patterns':[r".*: warning: ordered comparison of pointer with integer zero"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wwrite-strings',
+        'description':'Conversion of string constant to non-const char*',
+        'patterns':[r".*: warning: deprecated conversion from string constant to '.+'"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wstrict-prototypes',
+        'description':'Function declaration isn''t a prototype',
+        'patterns':[r".*: warning: function declaration isn't a prototype"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wignored-qualifiers',
+        'description':'Type qualifiers ignored on function return value',
+        'patterns':[r".*: warning: type qualifiers ignored on function return type"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'&lt;foo&gt; declared inside parameter list, scope limited to this definition',
+        'patterns':[r".*: warning: '.+' declared inside parameter list"] },
+    { 'category':'cont.',   'severity':severity.SKIP,     'members':[], 'option':'',
+        'description':'',
+        'patterns':[r".*: warning: its scope is only this definition or declaration, which is probably not what you want"] },
+    { 'category':'C/C++',   'severity':severity.LOW,      'members':[], 'option':'-Wcomment',
+        'description':'Line continuation inside comment',
+        'patterns':[r".*: warning: multi-line comment"] },
+    { 'category':'C/C++',   'severity':severity.LOW,      'members':[], 'option':'-Wcomment',
+        'description':'Comment inside comment',
+        'patterns':[r".*: warning: "".+"" within comment"] },
+    { 'category':'C/C++',   'severity':severity.HARMLESS, 'members':[], 'option':'',
+        'description':'Extra tokens after #endif',
+        'patterns':[r".*: warning: extra tokens at end of #endif directive"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wenum-compare',
+        'description':'Comparison between different enums',
+        'patterns':[r".*: warning: comparison between 'enum .+' and 'enum .+'"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wconversion',
+        'description':'Implicit conversion of negative number to unsigned type',
+        'patterns':[r".*: warning: converting negative value '.+' to '.+'"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Passing NULL as non-pointer argument',
+        'patterns':[r".*: warning: passing NULL to non-pointer argument [0-9]+ of '.+'"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wctor-dtor-privacy',
+        'description':'Class seems unusable because of private ctor/dtor' ,
+        'patterns':[r".*: warning: all member functions in class '.+' are private"] },
+    # skip this next one, because it only points out some RefBase-based classes where having a private destructor is perfectly fine
+    { 'category':'C/C++',   'severity':severity.SKIP,     'members':[], 'option':'-Wctor-dtor-privacy',
+        'description':'Class seems unusable because of private ctor/dtor' ,
+        'patterns':[r".*: warning: 'class .+' only defines a private destructor and has no friends"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wctor-dtor-privacy',
+        'description':'Class seems unusable because of private ctor/dtor' ,
+        'patterns':[r".*: warning: 'class .+' only defines private constructors and has no friends"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wpointer-arith',
+        'description':'void* used in arithmetic' ,
+        'patterns':[r".*: warning: pointer of type 'void \*' used in (arithmetic|subtraction)",
+                    r".*: warning: wrong type argument to increment"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,   'members':[], 'option':'-Wsign-promo',
+        'description':'Overload resolution chose to promote from unsigned or enum to signed type' ,
+        'patterns':[r".*: warning: passing '.+' chooses 'int' over '.* int'"] },
+    { 'category':'cont.',   'severity':severity.SKIP,     'members':[], 'option':'',
+        'description':'',
+        'patterns':[r".*: warning:   in call to '.+'"] },
+    { 'category':'C/C++',   'severity':severity.HIGH,     'members':[], 'option':'-Wextra',
+        'description':'Base should be explicitly initialized in copy constructor',
+        'patterns':[r".*: warning: base class '.+' should be explicitly initialized in the copy constructor"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,     'members':[], 'option':'',
+        'description':'Converting from <type> to <other type>',
+        'patterns':[r".*: warning: converting to '.+' from '.+'"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,     'members':[], 'option':'',
+        'description':'Return value from void function',
+        'patterns':[r".*: warning: 'return' with a value, in function returning void"] },
+    { 'category':'C/C++',   'severity':severity.LOW,     'members':[], 'option':'',
+        'description':'Useless specifier',
+        'patterns':[r".*: warning: useless storage class specifier in empty declaration"] },
+    { 'category':'logtags',   'severity':severity.LOW,     'members':[], 'option':'',
+        'description':'Duplicate logtag',
+        'patterns':[r".*: warning: tag "".+"" \(None\) duplicated in .+"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,     'members':[], 'option':'',
+        'description':'Operator new returns NULL',
+        'patterns':[r".*: warning: 'operator new' must not return NULL unless it is declared 'throw\(\)' .+"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,     'members':[], 'option':'',
+        'description':'NULL used in arithmetic',
+        'patterns':[r".*: warning: NULL used in arithmetic"] },
+    { 'category':'C/C++',   'severity':severity.MEDIUM,     'members':[], 'option':'',
+        'description':'Use of deprecated method',
+        'patterns':[r".*: warning: '.+' is deprecated .+"] },
+
+    # these next ones are to deal with formatting problems resulting from the log being mixed up by 'make -j'
+    { 'category':'C/C++',   'severity':severity.SKIP,     'members':[], 'option':'',
+        'description':'',
+        'patterns':[r".*: warning: ,$"] },
+    { 'category':'C/C++',   'severity':severity.SKIP,     'members':[], 'option':'',
+        'description':'',
+        'patterns':[r".*: warning: $"] },
+    { 'category':'C/C++',   'severity':severity.SKIP,     'members':[], 'option':'',
+        'description':'',
+        'patterns':[r".*: warning: In file included from .+,"] },
+
+    # catch-all for warnings this script doesn't know about yet
+    { 'category':'C/C++',   'severity':severity.UNKNOWN,  'members':[], 'option':'',
+        'description':'Unclassified/unrecognized warnings',
+        'patterns':[r".*: warning: .+"] },
+]
+
+anchor = 0
+cur_row_color = 0
+row_colors = [ 'e0e0e0', 'd0d0d0' ]
+
+def output(text):
+    print text,
+
+def htmlbig(param):
+    return '<font size="+2">' + param + '</font>'
+
+def dumphtmlprologue(title):
+    output('<html>\n<head>\n<title>' + title + '</title>\n<body>\n')
+    output(htmlbig(title))
+    output('<p>\n')
+
+def tablerow(text):
+    global cur_row_color
+    output('<tr bgcolor="' + row_colors[cur_row_color] + '"><td colspan="2">',)
+    cur_row_color = 1 - cur_row_color
+    output(text,)
+    output('</td></tr>')
+
+def begintable(text, backgroundcolor):
+    global anchor
+    output('<table border="1" rules="cols" frame="box" width="100%" bgcolor="black"><tr bgcolor="' +
+        backgroundcolor + '"><a name="anchor' + str(anchor) + '"><td>')
+    output(htmlbig(text[0]) + '<br>')
+    for i in text[1:]:
+        output(i + '<br>')
+    output('</td>')
+    output('<td width="100" bgcolor="grey"><a align="right" href="#anchor' + str(anchor-1) +
+        '">previous</a><br><a align="right" href="#anchor' + str(anchor+1) + '">next</a>')
+    output('</td></a></tr>')
+    anchor += 1
+
+def endtable():
+    output('</table><p>')
+
+
+# dump some stats about total number of warnings and such
+def dumpstats():
+    known = 0
+    unknown = 0
+    for i in warnpatterns:
+        if i['severity'] == severity.UNKNOWN:
+            unknown += len(i['members'])
+        elif i['severity'] != severity.SKIP:
+            known += len(i['members'])
+    output('Number of classified warnings: <b>' + str(known) + '</b><br>' )
+    output('Number of unclassified warnings: <b>' + str(unknown) + '</b><br>')
+    total = unknown + known
+    output('Total number of warnings: <b>' + str(total) + '</b>')
+    if total < 1000:
+        output('(low count may indicate incremental build)')
+    output('<p>')
+
+def allpatterns(cat):
+    pats = ''
+    for i in cat['patterns']:
+        pats += i
+        pats += ' / '
+    return pats
+
+def descriptionfor(cat):
+    if cat['description'] != '':
+        return cat['description']
+    return allpatterns(cat)
+
+
+# show which warnings no longer occur
+def dumpfixed():
+    tablestarted = False
+    for i in warnpatterns:
+        if len(i['members']) == 0 and i['severity'] != severity.SKIP:
+            if tablestarted == False:
+                tablestarted = True
+                begintable(['Fixed warnings', 'No more occurences. Please consider turning these in to errors if possible, before they are reintroduced in to the build'], 'blue')
+            tablerow(i['description'] + ' (' + allpatterns(i) + ') ' + i['option'])
+    if tablestarted:
+        endtable()
+
+
+# dump a category, provided it is not marked as 'SKIP' and has more than 0 occurrences
+def dumpcategory(cat):
+    if cat['severity'] != severity.SKIP and len(cat['members']) != 0:
+        header = [descriptionfor(cat),str(len(cat['members'])) + ' occurences:']
+        if cat['option'] != '':
+            header[1:1] = [' (related option: ' + cat['option'] +')']
+        begintable(header, colorforseverity(cat['severity']))
+        for i in cat['members']:
+            tablerow(i)
+        endtable()
+
+
+# dump everything for a given severity
+def dumpseverity(sev):
+    for i in warnpatterns:
+        if i['severity'] == sev:
+            dumpcategory(i)
+
+
+def classifywarning(line):
+    for i in warnpatterns:
+        for cpat in i['compiledpatterns']:
+            if cpat.match(line):
+                i['members'].append(line)
+                return
+    else:
+        # If we end up here, there was a problem parsing the log
+        # probably caused by 'make -j' mixing the output from
+        # 2 or more concurrent compiles
+        pass
+
+# precompiling every pattern speeds up parsing by about 30x
+def compilepatterns():
+    for i in warnpatterns:
+        i['compiledpatterns'] = []
+        for pat in i['patterns']:
+            i['compiledpatterns'].append(re.compile(pat))
+
+infile = open(sys.argv[1], 'r')
+warnings = []
+
+platformversion = 'unknown'
+targetproduct = 'unknown'
+targetvariant = 'unknown'
+linecounter = 0
+
+warningpattern = re.compile('.* warning:.*')
+compilepatterns()
+
+# read the log file and classify all the warnings
+lastmatchedline = ''
+for line in infile:
+    # replace fancy quotes with plain ol' quotes
+    line = line.replace("‘", "'");
+    line = line.replace("’", "'");
+    if warningpattern.match(line):
+        if line != lastmatchedline:
+            classifywarning(line)
+            lastmatchedline = line
+    else:
+        # save a little bit of time by only doing this for the first few lines
+        if linecounter < 50:
+            linecounter +=1
+            m = re.search('(?<=^PLATFORM_VERSION=).*', line)
+            if m != None:
+                platformversion = m.group(0)
+            m = re.search('(?<=^TARGET_PRODUCT=).*', line)
+            if m != None:
+                targetproduct = m.group(0)
+            m = re.search('(?<=^TARGET_BUILD_VARIANT=).*', line)
+            if m != None:
+                targetvariant = m.group(0)
+
+
+# dump the html output to stdout
+dumphtmlprologue('Warnings for ' + platformversion + ' - ' + targetproduct + ' - ' + targetvariant)
+dumpstats()
+dumpseverity(severity.FIXMENOW)
+dumpseverity(severity.HIGH)
+dumpseverity(severity.MEDIUM)
+dumpseverity(severity.LOW)
+dumpseverity(severity.HARMLESS)
+dumpseverity(severity.UNKNOWN)
+dumpfixed()
+
diff --git a/build/tools/zipalign/Android.mk b/build/tools/zipalign/Android.mk
new file mode 100644 (file)
index 0000000..9763bd2
--- /dev/null
@@ -0,0 +1,34 @@
+# 
+# Copyright 2008 The Android Open Source Project
+#
+# Zip alignment tool
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+       ZipAlign.cpp \
+       ZipEntry.cpp \
+       ZipFile.cpp
+
+LOCAL_C_INCLUDES += external/zlib
+
+LOCAL_STATIC_LIBRARIES := \
+       libutils \
+       libcutils
+
+ifeq ($(HOST_OS),linux)
+LOCAL_LDLIBS += -lrt
+endif
+
+ifneq ($(strip $(USE_MINGW)),)
+LOCAL_STATIC_LIBRARIES += libz
+else
+LOCAL_LDLIBS += -lz
+endif
+
+LOCAL_MODULE := zipalign
+
+include $(BUILD_HOST_EXECUTABLE)
+
diff --git a/build/tools/zipalign/README.txt b/build/tools/zipalign/README.txt
new file mode 100644 (file)
index 0000000..9c7d07e
--- /dev/null
@@ -0,0 +1,35 @@
+zipalign -- zip archive alignment tool
+
+usage: zipalign [-f] [-v] <align> infile.zip outfile.zip
+       zipalign -c [-v] <align> infile.zip
+
+  -c : check alignment only (does not modify file)
+  -f : overwrite existing outfile.zip
+  -v : verbose output
+  <align> is in bytes, e.g. "4" provides 32-bit alignment
+  infile.zip is an existing Zip archive
+  outfile.zip will be created
+
+
+The purpose of zipalign is to ensure that all uncompressed data starts
+with a particular alignment relative to the start of the file.  This
+allows those portions to be accessed directly with mmap() even if they
+contain binary data with alignment restrictions.
+
+Some data needs to be word-aligned for easy access, others might benefit
+from being page-aligned.  The adjustment is made by altering the size of
+the "extra" field in the zip Local File Header sections.  Existing data
+in the "extra" fields may be altered by this process.
+
+Compressed data isn't very useful until it's uncompressed, so there's no
+need to adjust its alignment.
+
+Alterations to the archive, such as renaming or deleting entries, will
+potentially disrupt the alignment of the modified entry and all later
+entries.  Files added to an "aligned" archive will not be aligned.
+
+By default, zipalign will not overwrite an existing output file.  With the
+"-f" flag, an existing file will be overwritten.
+
+You can use the "-c" flag to test whether a zip archive is properly aligned.
+
diff --git a/build/tools/zipalign/ZipAlign.cpp b/build/tools/zipalign/ZipAlign.cpp
new file mode 100644 (file)
index 0000000..c2d8159
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Zip alignment tool
+ */
+#include "ZipFile.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+using namespace android;
+
+/*
+ * Show program usage.
+ */
+void usage(void)
+{
+    fprintf(stderr, "Zip alignment utility\n");
+    fprintf(stderr, "Copyright (C) 2009 The Android Open Source Project\n\n");
+    fprintf(stderr,
+        "Usage: zipalign [-f] [-v] <align> infile.zip outfile.zip\n"
+        "       zipalign -c [-v] <align> infile.zip\n\n" );
+    fprintf(stderr,
+        "  <align>: alignment in bytes, e.g. '4' provides 32-bit alignment\n");
+    fprintf(stderr, "  -c: check alignment only (does not modify file)\n");
+    fprintf(stderr, "  -f: overwrite existing outfile.zip\n");
+    fprintf(stderr, "  -v: verbose output\n");
+}
+
+/*
+ * Copy all entries from "pZin" to "pZout", aligning as needed.
+ */
+static int copyAndAlign(ZipFile* pZin, ZipFile* pZout, int alignment)
+{
+    int numEntries = pZin->getNumEntries();
+    ZipEntry* pEntry;
+    int bias = 0;
+    status_t status;
+
+    for (int i = 0; i < numEntries; i++) {
+        ZipEntry* pNewEntry;
+        int padding = 0;
+
+        pEntry = pZin->getEntryByIndex(i);
+        if (pEntry == NULL) {
+            fprintf(stderr, "ERROR: unable to retrieve entry %d\n", i);
+            return 1;
+        }
+
+        if (pEntry->isCompressed()) {
+            /* copy the entry without padding */
+            //printf("--- %s: orig at %ld len=%ld (compressed)\n",
+            //    pEntry->getFileName(), (long) pEntry->getFileOffset(),
+            //    (long) pEntry->getUncompressedLen());
+
+        } else {
+            /*
+             * Copy the entry, adjusting as required.  We assume that the
+             * file position in the new file will be equal to the file
+             * position in the original.
+             */
+            long newOffset = pEntry->getFileOffset() + bias;
+            padding = (alignment - (newOffset % alignment)) % alignment;
+
+            //printf("--- %s: orig at %ld(+%d) len=%ld, adding pad=%d\n",
+            //    pEntry->getFileName(), (long) pEntry->getFileOffset(),
+            //    bias, (long) pEntry->getUncompressedLen(), padding);
+        }
+
+        status = pZout->add(pZin, pEntry, padding, &pNewEntry);
+        if (status != NO_ERROR)
+            return 1;
+        bias += padding;
+        //printf(" added '%s' at %ld (pad=%d)\n",
+        //    pNewEntry->getFileName(), (long) pNewEntry->getFileOffset(),
+        //    padding);
+    }
+
+    return 0;
+}
+
+/*
+ * Process a file.  We open the input and output files, failing if the
+ * output file exists and "force" wasn't specified.
+ */
+static int process(const char* inFileName, const char* outFileName,
+    int alignment, bool force)
+{
+    ZipFile zin, zout;
+
+    //printf("PROCESS: align=%d in='%s' out='%s' force=%d\n",
+    //    alignment, inFileName, outFileName, force);
+
+    /* this mode isn't supported -- do a trivial check */
+    if (strcmp(inFileName, outFileName) == 0) {
+        fprintf(stderr, "Input and output can't be same file\n");
+        return 1;
+    }
+
+    /* don't overwrite existing unless given permission */
+    if (!force && access(outFileName, F_OK) == 0) {
+        fprintf(stderr, "Output file '%s' exists\n", outFileName);
+        return 1;
+    }
+
+    if (zin.open(inFileName, ZipFile::kOpenReadOnly) != NO_ERROR) {
+        fprintf(stderr, "Unable to open '%s' as zip archive\n", inFileName);
+        return 1;
+    }
+    if (zout.open(outFileName,
+            ZipFile::kOpenReadWrite|ZipFile::kOpenCreate|ZipFile::kOpenTruncate)
+        != NO_ERROR)
+    {
+        fprintf(stderr, "Unable to open '%s' as zip archive\n", inFileName);
+        return 1;
+    }
+
+    int result = copyAndAlign(&zin, &zout, alignment);
+    if (result != 0) {
+        printf("zipalign: failed rewriting '%s' to '%s'\n",
+            inFileName, outFileName);
+    }
+    return result;
+}
+
+/*
+ * Verify the alignment of a zip archive.
+ */
+static int verify(const char* fileName, int alignment, bool verbose)
+{
+    ZipFile zipFile;
+    bool foundBad = false;
+
+    if (verbose)
+        printf("Verifying alignment of %s (%d)...\n", fileName, alignment);
+
+    if (zipFile.open(fileName, ZipFile::kOpenReadOnly) != NO_ERROR) {
+        fprintf(stderr, "Unable to open '%s' for verification\n", fileName);
+        return 1;
+    }
+
+    int numEntries = zipFile.getNumEntries();
+    ZipEntry* pEntry;
+
+    for (int i = 0; i < numEntries; i++) {
+        pEntry = zipFile.getEntryByIndex(i);
+        if (pEntry->isCompressed()) {
+            if (verbose) {
+                printf("%8ld %s (OK - compressed)\n",
+                    (long) pEntry->getFileOffset(), pEntry->getFileName());
+            }
+        } else {
+            long offset = pEntry->getFileOffset();
+            if ((offset % alignment) != 0) {
+                if (verbose) {
+                    printf("%8ld %s (BAD - %ld)\n",
+                        (long) offset, pEntry->getFileName(),
+                        offset % alignment);
+                }
+                foundBad = true;
+            } else {
+                if (verbose) {
+                    printf("%8ld %s (OK)\n",
+                        (long) offset, pEntry->getFileName());
+                }
+            }
+        }
+    }
+
+    if (verbose)
+        printf("Verification %s\n", foundBad ? "FAILED" : "succesful");
+
+    return foundBad ? 1 : 0;
+}
+
+/*
+ * Parse args.
+ */
+int main(int argc, char* const argv[])
+{
+    bool wantUsage = false;
+    bool check = false;
+    bool force = false;
+    bool verbose = false;
+    int result = 1;
+    int alignment;
+    char* endp;
+
+    if (argc < 4) {
+        wantUsage = true;
+        goto bail;
+    }
+
+    argc--;
+    argv++;
+
+    while (argc && argv[0][0] == '-') {
+        const char* cp = argv[0] +1;
+
+        while (*cp != '\0') {
+            switch (*cp) {
+            case 'c':
+                check = true;
+                break;
+            case 'f':
+                force = true;
+                break;
+            case 'v':
+                verbose = true;
+                break;
+            default:
+                fprintf(stderr, "ERROR: unknown flag -%c\n", *cp);
+                wantUsage = true;
+                goto bail;
+            }
+
+            cp++;
+        }
+
+        argc--;
+        argv++;
+    }
+
+    if (!((check && argc == 2) || (!check && argc == 3))) {
+        wantUsage = true;
+        goto bail;
+    }
+
+    alignment = strtol(argv[0], &endp, 10);
+    if (*endp != '\0' || alignment <= 0) {
+        fprintf(stderr, "Invalid value for alignment: %s\n", argv[0]);
+        wantUsage = true;
+        goto bail;
+    }
+
+    if (check) {
+        /* check existing archive for correct alignment */
+        result = verify(argv[1], alignment, verbose);
+    } else {
+        /* create the new archive */
+        result = process(argv[1], argv[2], alignment, force);
+
+        /* trust, but verify */
+        if (result == 0)
+            result = verify(argv[2], alignment, verbose);
+    }
+
+bail:
+    if (wantUsage) {
+        usage();
+        result = 2;
+    }
+
+    return result;
+}
diff --git a/build/tools/zipalign/ZipEntry.cpp b/build/tools/zipalign/ZipEntry.cpp
new file mode 100644 (file)
index 0000000..bed0333
--- /dev/null
@@ -0,0 +1,696 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Access to entries in a Zip archive.
+//
+
+#define LOG_TAG "zip"
+
+#include "ZipEntry.h"
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+using namespace android;
+
+/*
+ * Initialize a new ZipEntry structure from a FILE* positioned at a
+ * CentralDirectoryEntry.
+ *
+ * On exit, the file pointer will be at the start of the next CDE or
+ * at the EOCD.
+ */
+status_t ZipEntry::initFromCDE(FILE* fp)
+{
+    status_t result;
+    long posn;
+    bool hasDD;
+
+    //LOGV("initFromCDE ---\n");
+
+    /* read the CDE */
+    result = mCDE.read(fp);
+    if (result != NO_ERROR) {
+        LOGD("mCDE.read failed\n");
+        return result;
+    }
+
+    //mCDE.dump();
+
+    /* using the info in the CDE, go load up the LFH */
+    posn = ftell(fp);
+    if (fseek(fp, mCDE.mLocalHeaderRelOffset, SEEK_SET) != 0) {
+        LOGD("local header seek failed (%ld)\n",
+            mCDE.mLocalHeaderRelOffset);
+        return UNKNOWN_ERROR;
+    }
+
+    result = mLFH.read(fp);
+    if (result != NO_ERROR) {
+        LOGD("mLFH.read failed\n");
+        return result;
+    }
+
+    if (fseek(fp, posn, SEEK_SET) != 0)
+        return UNKNOWN_ERROR;
+
+    //mLFH.dump();
+
+    /*
+     * We *might* need to read the Data Descriptor at this point and
+     * integrate it into the LFH.  If this bit is set, the CRC-32,
+     * compressed size, and uncompressed size will be zero.  In practice
+     * these seem to be rare.
+     */
+    hasDD = (mLFH.mGPBitFlag & kUsesDataDescr) != 0;
+    if (hasDD) {
+        // do something clever
+        //LOGD("+++ has data descriptor\n");
+    }
+
+    /*
+     * Sanity-check the LFH.  Note that this will fail if the "kUsesDataDescr"
+     * flag is set, because the LFH is incomplete.  (Not a problem, since we
+     * prefer the CDE values.)
+     */
+    if (!hasDD && !compareHeaders()) {
+        LOGW("WARNING: header mismatch\n");
+        // keep going?
+    }
+
+    /*
+     * If the mVersionToExtract is greater than 20, we may have an
+     * issue unpacking the record -- could be encrypted, compressed
+     * with something we don't support, or use Zip64 extensions.  We
+     * can defer worrying about that to when we're extracting data.
+     */
+
+    return NO_ERROR;
+}
+
+/*
+ * Initialize a new entry.  Pass in the file name and an optional comment.
+ *
+ * Initializes the CDE and the LFH.
+ */
+void ZipEntry::initNew(const char* fileName, const char* comment)
+{
+    assert(fileName != NULL && *fileName != '\0');  // name required
+
+    /* most fields are properly initialized by constructor */
+    mCDE.mVersionMadeBy = kDefaultMadeBy;
+    mCDE.mVersionToExtract = kDefaultVersion;
+    mCDE.mCompressionMethod = kCompressStored;
+    mCDE.mFileNameLength = strlen(fileName);
+    if (comment != NULL)
+        mCDE.mFileCommentLength = strlen(comment);
+    mCDE.mExternalAttrs = 0x81b60020;   // matches what WinZip does
+
+    if (mCDE.mFileNameLength > 0) {
+        mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
+        strcpy((char*) mCDE.mFileName, fileName);
+    }
+    if (mCDE.mFileCommentLength > 0) {
+        /* TODO: stop assuming null-terminated ASCII here? */
+        mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
+        strcpy((char*) mCDE.mFileComment, comment);
+    }
+
+    copyCDEtoLFH();
+}
+
+/*
+ * Initialize a new entry, starting with the ZipEntry from a different
+ * archive.
+ *
+ * Initializes the CDE and the LFH.
+ */
+status_t ZipEntry::initFromExternal(const ZipFile* pZipFile,
+    const ZipEntry* pEntry)
+{
+    /*
+     * Copy everything in the CDE over, then fix up the hairy bits.
+     */
+    memcpy(&mCDE, &pEntry->mCDE, sizeof(mCDE));
+
+    if (mCDE.mFileNameLength > 0) {
+        mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
+        if (mCDE.mFileName == NULL)
+            return NO_MEMORY;
+        strcpy((char*) mCDE.mFileName, (char*)pEntry->mCDE.mFileName);
+    }
+    if (mCDE.mFileCommentLength > 0) {
+        mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
+        if (mCDE.mFileComment == NULL)
+            return NO_MEMORY;
+        strcpy((char*) mCDE.mFileComment, (char*)pEntry->mCDE.mFileComment);
+    }
+    if (mCDE.mExtraFieldLength > 0) {
+        /* we null-terminate this, though it may not be a string */
+        mCDE.mExtraField = new unsigned char[mCDE.mExtraFieldLength+1];
+        if (mCDE.mExtraField == NULL)
+            return NO_MEMORY;
+        memcpy(mCDE.mExtraField, pEntry->mCDE.mExtraField,
+            mCDE.mExtraFieldLength+1);
+    }
+
+    /* construct the LFH from the CDE */
+    copyCDEtoLFH();
+
+    /*
+     * The LFH "extra" field is independent of the CDE "extra", so we
+     * handle it here.
+     */
+    assert(mLFH.mExtraField == NULL);
+    mLFH.mExtraFieldLength = pEntry->mLFH.mExtraFieldLength;
+    if (mLFH.mExtraFieldLength > 0) {
+        mLFH.mExtraField = new unsigned char[mLFH.mExtraFieldLength+1];
+        if (mLFH.mExtraField == NULL)
+            return NO_MEMORY;
+        memcpy(mLFH.mExtraField, pEntry->mLFH.mExtraField,
+            mLFH.mExtraFieldLength+1);
+    }
+
+    return NO_ERROR;
+}
+
+/*
+ * Insert pad bytes in the LFH by tweaking the "extra" field.  This will
+ * potentially confuse something that put "extra" data in here earlier,
+ * but I can't find an actual problem.
+ */
+status_t ZipEntry::addPadding(int padding)
+{
+    if (padding <= 0)
+        return INVALID_OPERATION;
+
+    //LOGI("HEY: adding %d pad bytes to existing %d in %s\n",
+    //    padding, mLFH.mExtraFieldLength, mCDE.mFileName);
+
+    if (mLFH.mExtraFieldLength > 0) {
+        /* extend existing field */
+        unsigned char* newExtra;
+
+        newExtra = new unsigned char[mLFH.mExtraFieldLength + padding];
+        if (newExtra == NULL)
+            return NO_MEMORY;
+        memset(newExtra + mLFH.mExtraFieldLength, 0, padding);
+        memcpy(newExtra, mLFH.mExtraField, mLFH.mExtraFieldLength);
+
+        delete[] mLFH.mExtraField;
+        mLFH.mExtraField = newExtra;
+        mLFH.mExtraFieldLength += padding;
+    } else {
+        /* create new field */
+        mLFH.mExtraField = new unsigned char[padding];
+        memset(mLFH.mExtraField, 0, padding);
+        mLFH.mExtraFieldLength = padding;
+    }
+
+    return NO_ERROR;
+}
+
+/*
+ * Set the fields in the LFH equal to the corresponding fields in the CDE.
+ *
+ * This does not touch the LFH "extra" field.
+ */
+void ZipEntry::copyCDEtoLFH(void)
+{
+    mLFH.mVersionToExtract  = mCDE.mVersionToExtract;
+    mLFH.mGPBitFlag         = mCDE.mGPBitFlag;
+    mLFH.mCompressionMethod = mCDE.mCompressionMethod;
+    mLFH.mLastModFileTime   = mCDE.mLastModFileTime;
+    mLFH.mLastModFileDate   = mCDE.mLastModFileDate;
+    mLFH.mCRC32             = mCDE.mCRC32;
+    mLFH.mCompressedSize    = mCDE.mCompressedSize;
+    mLFH.mUncompressedSize  = mCDE.mUncompressedSize;
+    mLFH.mFileNameLength    = mCDE.mFileNameLength;
+    // the "extra field" is independent
+
+    delete[] mLFH.mFileName;
+    if (mLFH.mFileNameLength > 0) {
+        mLFH.mFileName = new unsigned char[mLFH.mFileNameLength+1];
+        strcpy((char*) mLFH.mFileName, (const char*) mCDE.mFileName);
+    } else {
+        mLFH.mFileName = NULL;
+    }
+}
+
+/*
+ * Set some information about a file after we add it.
+ */
+void ZipEntry::setDataInfo(long uncompLen, long compLen, unsigned long crc32,
+    int compressionMethod)
+{
+    mCDE.mCompressionMethod = compressionMethod;
+    mCDE.mCRC32 = crc32;
+    mCDE.mCompressedSize = compLen;
+    mCDE.mUncompressedSize = uncompLen;
+    mCDE.mCompressionMethod = compressionMethod;
+    if (compressionMethod == kCompressDeflated) {
+        mCDE.mGPBitFlag |= 0x0002;      // indicates maximum compression used
+    }
+    copyCDEtoLFH();
+}
+
+/*
+ * See if the data in mCDE and mLFH match up.  This is mostly useful for
+ * debugging these classes, but it can be used to identify damaged
+ * archives.
+ *
+ * Returns "false" if they differ.
+ */
+bool ZipEntry::compareHeaders(void) const
+{
+    if (mCDE.mVersionToExtract != mLFH.mVersionToExtract) {
+        LOGV("cmp: VersionToExtract\n");
+        return false;
+    }
+    if (mCDE.mGPBitFlag != mLFH.mGPBitFlag) {
+        LOGV("cmp: GPBitFlag\n");
+        return false;
+    }
+    if (mCDE.mCompressionMethod != mLFH.mCompressionMethod) {
+        LOGV("cmp: CompressionMethod\n");
+        return false;
+    }
+    if (mCDE.mLastModFileTime != mLFH.mLastModFileTime) {
+        LOGV("cmp: LastModFileTime\n");
+        return false;
+    }
+    if (mCDE.mLastModFileDate != mLFH.mLastModFileDate) {
+        LOGV("cmp: LastModFileDate\n");
+        return false;
+    }
+    if (mCDE.mCRC32 != mLFH.mCRC32) {
+        LOGV("cmp: CRC32\n");
+        return false;
+    }
+    if (mCDE.mCompressedSize != mLFH.mCompressedSize) {
+        LOGV("cmp: CompressedSize\n");
+        return false;
+    }
+    if (mCDE.mUncompressedSize != mLFH.mUncompressedSize) {
+        LOGV("cmp: UncompressedSize\n");
+        return false;
+    }
+    if (mCDE.mFileNameLength != mLFH.mFileNameLength) {
+        LOGV("cmp: FileNameLength\n");
+        return false;
+    }
+#if 0       // this seems to be used for padding, not real data
+    if (mCDE.mExtraFieldLength != mLFH.mExtraFieldLength) {
+        LOGV("cmp: ExtraFieldLength\n");
+        return false;
+    }
+#endif
+    if (mCDE.mFileName != NULL) {
+        if (strcmp((char*) mCDE.mFileName, (char*) mLFH.mFileName) != 0) {
+            LOGV("cmp: FileName\n");
+            return false;
+        }
+    }
+
+    return true;
+}
+
+
+/*
+ * Convert the DOS date/time stamp into a UNIX time stamp.
+ */
+time_t ZipEntry::getModWhen(void) const
+{
+    struct tm parts;
+
+    parts.tm_sec = (mCDE.mLastModFileTime & 0x001f) << 1;
+    parts.tm_min = (mCDE.mLastModFileTime & 0x07e0) >> 5;
+    parts.tm_hour = (mCDE.mLastModFileTime & 0xf800) >> 11;
+    parts.tm_mday = (mCDE.mLastModFileDate & 0x001f);
+    parts.tm_mon = ((mCDE.mLastModFileDate & 0x01e0) >> 5) -1;
+    parts.tm_year = ((mCDE.mLastModFileDate & 0xfe00) >> 9) + 80;
+    parts.tm_wday = parts.tm_yday = 0;
+    parts.tm_isdst = -1;        // DST info "not available"
+
+    return mktime(&parts);
+}
+
+/*
+ * Set the CDE/LFH timestamp from UNIX time.
+ */
+void ZipEntry::setModWhen(time_t when)
+{
+#ifdef HAVE_LOCALTIME_R
+    struct tm tmResult;
+#endif
+    time_t even;
+    unsigned short zdate, ztime;
+
+    struct tm* ptm;
+
+    /* round up to an even number of seconds */
+    even = (time_t)(((unsigned long)(when) + 1) & (~1));
+
+    /* expand */
+#ifdef HAVE_LOCALTIME_R
+    ptm = localtime_r(&even, &tmResult);
+#else
+    ptm = localtime(&even);
+#endif
+
+    int year;
+    year = ptm->tm_year;
+    if (year < 80)
+        year = 80;
+
+    zdate = (year - 80) << 9 | (ptm->tm_mon+1) << 5 | ptm->tm_mday;
+    ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
+
+    mCDE.mLastModFileTime = mLFH.mLastModFileTime = ztime;
+    mCDE.mLastModFileDate = mLFH.mLastModFileDate = zdate;
+}
+
+
+/*
+ * ===========================================================================
+ *      ZipEntry::LocalFileHeader
+ * ===========================================================================
+ */
+
+/*
+ * Read a local file header.
+ *
+ * On entry, "fp" points to the signature at the start of the header.
+ * On exit, "fp" points to the start of data.
+ */
+status_t ZipEntry::LocalFileHeader::read(FILE* fp)
+{
+    status_t result = NO_ERROR;
+    unsigned char buf[kLFHLen];
+
+    assert(mFileName == NULL);
+    assert(mExtraField == NULL);
+
+    if (fread(buf, 1, kLFHLen, fp) != kLFHLen) {
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
+        LOGD("whoops: didn't find expected signature\n");
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    mVersionToExtract = ZipEntry::getShortLE(&buf[0x04]);
+    mGPBitFlag = ZipEntry::getShortLE(&buf[0x06]);
+    mCompressionMethod = ZipEntry::getShortLE(&buf[0x08]);
+    mLastModFileTime = ZipEntry::getShortLE(&buf[0x0a]);
+    mLastModFileDate = ZipEntry::getShortLE(&buf[0x0c]);
+    mCRC32 = ZipEntry::getLongLE(&buf[0x0e]);
+    mCompressedSize = ZipEntry::getLongLE(&buf[0x12]);
+    mUncompressedSize = ZipEntry::getLongLE(&buf[0x16]);
+    mFileNameLength = ZipEntry::getShortLE(&buf[0x1a]);
+    mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1c]);
+
+    // TODO: validate sizes
+
+    /* grab filename */
+    if (mFileNameLength != 0) {
+        mFileName = new unsigned char[mFileNameLength+1];
+        if (mFileName == NULL) {
+            result = NO_MEMORY;
+            goto bail;
+        }
+        if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
+            result = UNKNOWN_ERROR;
+            goto bail;
+        }
+        mFileName[mFileNameLength] = '\0';
+    }
+
+    /* grab extra field */
+    if (mExtraFieldLength != 0) {
+        mExtraField = new unsigned char[mExtraFieldLength+1];
+        if (mExtraField == NULL) {
+            result = NO_MEMORY;
+            goto bail;
+        }
+        if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
+            result = UNKNOWN_ERROR;
+            goto bail;
+        }
+        mExtraField[mExtraFieldLength] = '\0';
+    }
+
+bail:
+    return result;
+}
+
+/*
+ * Write a local file header.
+ */
+status_t ZipEntry::LocalFileHeader::write(FILE* fp)
+{
+    unsigned char buf[kLFHLen];
+
+    ZipEntry::putLongLE(&buf[0x00], kSignature);
+    ZipEntry::putShortLE(&buf[0x04], mVersionToExtract);
+    ZipEntry::putShortLE(&buf[0x06], mGPBitFlag);
+    ZipEntry::putShortLE(&buf[0x08], mCompressionMethod);
+    ZipEntry::putShortLE(&buf[0x0a], mLastModFileTime);
+    ZipEntry::putShortLE(&buf[0x0c], mLastModFileDate);
+    ZipEntry::putLongLE(&buf[0x0e], mCRC32);
+    ZipEntry::putLongLE(&buf[0x12], mCompressedSize);
+    ZipEntry::putLongLE(&buf[0x16], mUncompressedSize);
+    ZipEntry::putShortLE(&buf[0x1a], mFileNameLength);
+    ZipEntry::putShortLE(&buf[0x1c], mExtraFieldLength);
+
+    if (fwrite(buf, 1, kLFHLen, fp) != kLFHLen)
+        return UNKNOWN_ERROR;
+
+    /* write filename */
+    if (mFileNameLength != 0) {
+        if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
+            return UNKNOWN_ERROR;
+    }
+
+    /* write "extra field" */
+    if (mExtraFieldLength != 0) {
+        if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
+            return UNKNOWN_ERROR;
+    }
+
+    return NO_ERROR;
+}
+
+
+/*
+ * Dump the contents of a LocalFileHeader object.
+ */
+void ZipEntry::LocalFileHeader::dump(void) const
+{
+    LOGD(" LocalFileHeader contents:\n");
+    LOGD("  versToExt=%u gpBits=0x%04x compression=%u\n",
+        mVersionToExtract, mGPBitFlag, mCompressionMethod);
+    LOGD("  modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
+        mLastModFileTime, mLastModFileDate, mCRC32);
+    LOGD("  compressedSize=%lu uncompressedSize=%lu\n",
+        mCompressedSize, mUncompressedSize);
+    LOGD("  filenameLen=%u extraLen=%u\n",
+        mFileNameLength, mExtraFieldLength);
+    if (mFileName != NULL)
+        LOGD("  filename: '%s'\n", mFileName);
+}
+
+
+/*
+ * ===========================================================================
+ *      ZipEntry::CentralDirEntry
+ * ===========================================================================
+ */
+
+/*
+ * Read the central dir entry that appears next in the file.
+ *
+ * On entry, "fp" should be positioned on the signature bytes for the
+ * entry.  On exit, "fp" will point at the signature word for the next
+ * entry or for the EOCD.
+ */
+status_t ZipEntry::CentralDirEntry::read(FILE* fp)
+{
+    status_t result = NO_ERROR;
+    unsigned char buf[kCDELen];
+
+    /* no re-use */
+    assert(mFileName == NULL);
+    assert(mExtraField == NULL);
+    assert(mFileComment == NULL);
+
+    if (fread(buf, 1, kCDELen, fp) != kCDELen) {
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
+        LOGD("Whoops: didn't find expected signature\n");
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    mVersionMadeBy = ZipEntry::getShortLE(&buf[0x04]);
+    mVersionToExtract = ZipEntry::getShortLE(&buf[0x06]);
+    mGPBitFlag = ZipEntry::getShortLE(&buf[0x08]);
+    mCompressionMethod = ZipEntry::getShortLE(&buf[0x0a]);
+    mLastModFileTime = ZipEntry::getShortLE(&buf[0x0c]);
+    mLastModFileDate = ZipEntry::getShortLE(&buf[0x0e]);
+    mCRC32 = ZipEntry::getLongLE(&buf[0x10]);
+    mCompressedSize = ZipEntry::getLongLE(&buf[0x14]);
+    mUncompressedSize = ZipEntry::getLongLE(&buf[0x18]);
+    mFileNameLength = ZipEntry::getShortLE(&buf[0x1c]);
+    mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1e]);
+    mFileCommentLength = ZipEntry::getShortLE(&buf[0x20]);
+    mDiskNumberStart = ZipEntry::getShortLE(&buf[0x22]);
+    mInternalAttrs = ZipEntry::getShortLE(&buf[0x24]);
+    mExternalAttrs = ZipEntry::getLongLE(&buf[0x26]);
+    mLocalHeaderRelOffset = ZipEntry::getLongLE(&buf[0x2a]);
+
+    // TODO: validate sizes and offsets
+
+    /* grab filename */
+    if (mFileNameLength != 0) {
+        mFileName = new unsigned char[mFileNameLength+1];
+        if (mFileName == NULL) {
+            result = NO_MEMORY;
+            goto bail;
+        }
+        if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
+            result = UNKNOWN_ERROR;
+            goto bail;
+        }
+        mFileName[mFileNameLength] = '\0';
+    }
+
+    /* read "extra field" */
+    if (mExtraFieldLength != 0) {
+        mExtraField = new unsigned char[mExtraFieldLength+1];
+        if (mExtraField == NULL) {
+            result = NO_MEMORY;
+            goto bail;
+        }
+        if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
+            result = UNKNOWN_ERROR;
+            goto bail;
+        }
+        mExtraField[mExtraFieldLength] = '\0';
+    }
+
+
+    /* grab comment, if any */
+    if (mFileCommentLength != 0) {
+        mFileComment = new unsigned char[mFileCommentLength+1];
+        if (mFileComment == NULL) {
+            result = NO_MEMORY;
+            goto bail;
+        }
+        if (fread(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
+        {
+            result = UNKNOWN_ERROR;
+            goto bail;
+        }
+        mFileComment[mFileCommentLength] = '\0';
+    }
+
+bail:
+    return result;
+}
+
+/*
+ * Write a central dir entry.
+ */
+status_t ZipEntry::CentralDirEntry::write(FILE* fp)
+{
+    unsigned char buf[kCDELen];
+
+    ZipEntry::putLongLE(&buf[0x00], kSignature);
+    ZipEntry::putShortLE(&buf[0x04], mVersionMadeBy);
+    ZipEntry::putShortLE(&buf[0x06], mVersionToExtract);
+    ZipEntry::putShortLE(&buf[0x08], mGPBitFlag);
+    ZipEntry::putShortLE(&buf[0x0a], mCompressionMethod);
+    ZipEntry::putShortLE(&buf[0x0c], mLastModFileTime);
+    ZipEntry::putShortLE(&buf[0x0e], mLastModFileDate);
+    ZipEntry::putLongLE(&buf[0x10], mCRC32);
+    ZipEntry::putLongLE(&buf[0x14], mCompressedSize);
+    ZipEntry::putLongLE(&buf[0x18], mUncompressedSize);
+    ZipEntry::putShortLE(&buf[0x1c], mFileNameLength);
+    ZipEntry::putShortLE(&buf[0x1e], mExtraFieldLength);
+    ZipEntry::putShortLE(&buf[0x20], mFileCommentLength);
+    ZipEntry::putShortLE(&buf[0x22], mDiskNumberStart);
+    ZipEntry::putShortLE(&buf[0x24], mInternalAttrs);
+    ZipEntry::putLongLE(&buf[0x26], mExternalAttrs);
+    ZipEntry::putLongLE(&buf[0x2a], mLocalHeaderRelOffset);
+
+    if (fwrite(buf, 1, kCDELen, fp) != kCDELen)
+        return UNKNOWN_ERROR;
+
+    /* write filename */
+    if (mFileNameLength != 0) {
+        if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
+            return UNKNOWN_ERROR;
+    }
+
+    /* write "extra field" */
+    if (mExtraFieldLength != 0) {
+        if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
+            return UNKNOWN_ERROR;
+    }
+
+    /* write comment */
+    if (mFileCommentLength != 0) {
+        if (fwrite(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
+            return UNKNOWN_ERROR;
+    }
+
+    return NO_ERROR;
+}
+
+/*
+ * Dump the contents of a CentralDirEntry object.
+ */
+void ZipEntry::CentralDirEntry::dump(void) const
+{
+    LOGD(" CentralDirEntry contents:\n");
+    LOGD("  versMadeBy=%u versToExt=%u gpBits=0x%04x compression=%u\n",
+        mVersionMadeBy, mVersionToExtract, mGPBitFlag, mCompressionMethod);
+    LOGD("  modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
+        mLastModFileTime, mLastModFileDate, mCRC32);
+    LOGD("  compressedSize=%lu uncompressedSize=%lu\n",
+        mCompressedSize, mUncompressedSize);
+    LOGD("  filenameLen=%u extraLen=%u commentLen=%u\n",
+        mFileNameLength, mExtraFieldLength, mFileCommentLength);
+    LOGD("  diskNumStart=%u intAttr=0x%04x extAttr=0x%08lx relOffset=%lu\n",
+        mDiskNumberStart, mInternalAttrs, mExternalAttrs,
+        mLocalHeaderRelOffset);
+
+    if (mFileName != NULL)
+        LOGD("  filename: '%s'\n", mFileName);
+    if (mFileComment != NULL)
+        LOGD("  comment: '%s'\n", mFileComment);
+}
+
diff --git a/build/tools/zipalign/ZipEntry.h b/build/tools/zipalign/ZipEntry.h
new file mode 100644 (file)
index 0000000..7f721b4
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Zip archive entries.
+//
+// The ZipEntry class is tightly meshed with the ZipFile class.
+//
+#ifndef __LIBS_ZIPENTRY_H
+#define __LIBS_ZIPENTRY_H
+
+#include <utils/Errors.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+namespace android {
+
+class ZipFile;
+
+/*
+ * ZipEntry objects represent a single entry in a Zip archive.
+ *
+ * You can use one of these to get or set information about an entry, but
+ * there are no functions here for accessing the data itself.  (We could
+ * tuck a pointer to the ZipFile in here for convenience, but that raises
+ * the likelihood of using ZipEntry objects after discarding the ZipFile.)
+ *
+ * File information is stored in two places: next to the file data (the Local
+ * File Header, and possibly a Data Descriptor), and at the end of the file
+ * (the Central Directory Entry).  The two must be kept in sync.
+ */
+class ZipEntry {
+public:
+    friend class ZipFile;
+
+    ZipEntry(void)
+        : mDeleted(false), mMarked(false)
+        {}
+    ~ZipEntry(void) {}
+
+    /*
+     * Returns "true" if the data is compressed.
+     */
+    bool isCompressed(void) const {
+        return mCDE.mCompressionMethod != kCompressStored;
+    }
+    int getCompressionMethod(void) const { return mCDE.mCompressionMethod; }
+
+    /*
+     * Return the uncompressed length.
+     */
+    off_t getUncompressedLen(void) const { return mCDE.mUncompressedSize; }
+
+    /*
+     * Return the compressed length.  For uncompressed data, this returns
+     * the same thing as getUncompresesdLen().
+     */
+    off_t getCompressedLen(void) const { return mCDE.mCompressedSize; }
+
+    /*
+     * Return the absolute file offset of the start of the compressed or
+     * uncompressed data.
+     */
+    off_t getFileOffset(void) const {
+        return mCDE.mLocalHeaderRelOffset +
+                LocalFileHeader::kLFHLen +
+                mLFH.mFileNameLength +
+                mLFH.mExtraFieldLength;
+    }
+
+    /*
+     * Return the data CRC.
+     */
+    unsigned long getCRC32(void) const { return mCDE.mCRC32; }
+
+    /*
+     * Return file modification time in UNIX seconds-since-epoch.
+     */
+    time_t getModWhen(void) const;
+
+    /*
+     * Return the archived file name.
+     */
+    const char* getFileName(void) const { return (const char*) mCDE.mFileName; }
+
+    /*
+     * Application-defined "mark".  Can be useful when synchronizing the
+     * contents of an archive with contents on disk.
+     */
+    bool getMarked(void) const { return mMarked; }
+    void setMarked(bool val) { mMarked = val; }
+
+    /*
+     * Some basic functions for raw data manipulation.  "LE" means
+     * Little Endian.
+     */
+    static inline unsigned short getShortLE(const unsigned char* buf) {
+        return buf[0] | (buf[1] << 8);
+    }
+    static inline unsigned long getLongLE(const unsigned char* buf) {
+        return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+    }
+    static inline void putShortLE(unsigned char* buf, short val) {
+        buf[0] = (unsigned char) val;
+        buf[1] = (unsigned char) (val >> 8);
+    }
+    static inline void putLongLE(unsigned char* buf, long val) {
+        buf[0] = (unsigned char) val;
+        buf[1] = (unsigned char) (val >> 8);
+        buf[2] = (unsigned char) (val >> 16);
+        buf[3] = (unsigned char) (val >> 24);
+    }
+
+    /* defined for Zip archives */
+    enum {
+        kCompressStored     = 0,        // no compression
+        // shrunk           = 1,
+        // reduced 1        = 2,
+        // reduced 2        = 3,
+        // reduced 3        = 4,
+        // reduced 4        = 5,
+        // imploded         = 6,
+        // tokenized        = 7,
+        kCompressDeflated   = 8,        // standard deflate
+        // Deflate64        = 9,
+        // lib imploded     = 10,
+        // reserved         = 11,
+        // bzip2            = 12,
+    };
+
+    /*
+     * Deletion flag.  If set, the entry will be removed on the next
+     * call to "flush".
+     */
+    bool getDeleted(void) const { return mDeleted; }
+
+protected:
+    /*
+     * Initialize the structure from the file, which is pointing at
+     * our Central Directory entry.
+     */
+    status_t initFromCDE(FILE* fp);
+
+    /*
+     * Initialize the structure for a new file.  We need the filename
+     * and comment so that we can properly size the LFH area.  The
+     * filename is mandatory, the comment is optional.
+     */
+    void initNew(const char* fileName, const char* comment);
+
+    /*
+     * Initialize the structure with the contents of a ZipEntry from
+     * another file.
+     */
+    status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry);
+
+    /*
+     * Add some pad bytes to the LFH.  We do this by adding or resizing
+     * the "extra" field.
+     */
+    status_t addPadding(int padding);
+
+    /*
+     * Set information about the data for this entry.
+     */
+    void setDataInfo(long uncompLen, long compLen, unsigned long crc32,
+        int compressionMethod);
+
+    /*
+     * Set the modification date.
+     */
+    void setModWhen(time_t when);
+
+    /*
+     * Return the offset of the local file header.
+     */
+    off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; }
+
+    /*
+     * Set the offset of the local file header, relative to the start of
+     * the current file.
+     */
+    void setLFHOffset(off_t offset) {
+        mCDE.mLocalHeaderRelOffset = (long) offset;
+    }
+
+    /* mark for deletion; used by ZipFile::remove() */
+    void setDeleted(void) { mDeleted = true; }
+
+private:
+    /* these are private and not defined */
+    ZipEntry(const ZipEntry& src);
+    ZipEntry& operator=(const ZipEntry& src);
+
+    /* returns "true" if the CDE and the LFH agree */
+    bool compareHeaders(void) const;
+    void copyCDEtoLFH(void);
+
+    bool        mDeleted;       // set if entry is pending deletion
+    bool        mMarked;        // app-defined marker
+
+    /*
+     * Every entry in the Zip archive starts off with one of these.
+     */
+    class LocalFileHeader {
+    public:
+        LocalFileHeader(void) :
+            mVersionToExtract(0),
+            mGPBitFlag(0),
+            mCompressionMethod(0),
+            mLastModFileTime(0),
+            mLastModFileDate(0),
+            mCRC32(0),
+            mCompressedSize(0),
+            mUncompressedSize(0),
+            mFileNameLength(0),
+            mExtraFieldLength(0),
+            mFileName(NULL),
+            mExtraField(NULL)
+        {}
+        virtual ~LocalFileHeader(void) {
+            delete[] mFileName;
+            delete[] mExtraField;
+        }
+
+        status_t read(FILE* fp);
+        status_t write(FILE* fp);
+
+        // unsigned long mSignature;
+        unsigned short  mVersionToExtract;
+        unsigned short  mGPBitFlag;
+        unsigned short  mCompressionMethod;
+        unsigned short  mLastModFileTime;
+        unsigned short  mLastModFileDate;
+        unsigned long   mCRC32;
+        unsigned long   mCompressedSize;
+        unsigned long   mUncompressedSize;
+        unsigned short  mFileNameLength;
+        unsigned short  mExtraFieldLength;
+        unsigned char*  mFileName;
+        unsigned char*  mExtraField;
+
+        enum {
+            kSignature      = 0x04034b50,
+            kLFHLen         = 30,       // LocalFileHdr len, excl. var fields
+        };
+
+        void dump(void) const;
+    };
+
+    /*
+     * Every entry in the Zip archive has one of these in the "central
+     * directory" at the end of the file.
+     */
+    class CentralDirEntry {
+    public:
+        CentralDirEntry(void) :
+            mVersionMadeBy(0),
+            mVersionToExtract(0),
+            mGPBitFlag(0),
+            mCompressionMethod(0),
+            mLastModFileTime(0),
+            mLastModFileDate(0),
+            mCRC32(0),
+            mCompressedSize(0),
+            mUncompressedSize(0),
+            mFileNameLength(0),
+            mExtraFieldLength(0),
+            mFileCommentLength(0),
+            mDiskNumberStart(0),
+            mInternalAttrs(0),
+            mExternalAttrs(0),
+            mLocalHeaderRelOffset(0),
+            mFileName(NULL),
+            mExtraField(NULL),
+            mFileComment(NULL)
+        {}
+        virtual ~CentralDirEntry(void) {
+            delete[] mFileName;
+            delete[] mExtraField;
+            delete[] mFileComment;
+        }
+
+        status_t read(FILE* fp);
+        status_t write(FILE* fp);
+
+        // unsigned long mSignature;
+        unsigned short  mVersionMadeBy;
+        unsigned short  mVersionToExtract;
+        unsigned short  mGPBitFlag;
+        unsigned short  mCompressionMethod;
+        unsigned short  mLastModFileTime;
+        unsigned short  mLastModFileDate;
+        unsigned long   mCRC32;
+        unsigned long   mCompressedSize;
+        unsigned long   mUncompressedSize;
+        unsigned short  mFileNameLength;
+        unsigned short  mExtraFieldLength;
+        unsigned short  mFileCommentLength;
+        unsigned short  mDiskNumberStart;
+        unsigned short  mInternalAttrs;
+        unsigned long   mExternalAttrs;
+        unsigned long   mLocalHeaderRelOffset;
+        unsigned char*  mFileName;
+        unsigned char*  mExtraField;
+        unsigned char*  mFileComment;
+
+        void dump(void) const;
+
+        enum {
+            kSignature      = 0x02014b50,
+            kCDELen         = 46,       // CentralDirEnt len, excl. var fields
+        };
+    };
+
+    enum {
+        //kDataDescriptorSignature  = 0x08074b50,   // currently unused
+        kDataDescriptorLen  = 16,           // four 32-bit fields
+
+        kDefaultVersion     = 20,           // need deflate, nothing much else
+        kDefaultMadeBy      = 0x0317,       // 03=UNIX, 17=spec v2.3
+        kUsesDataDescr      = 0x0008,       // GPBitFlag bit 3
+    };
+
+    LocalFileHeader     mLFH;
+    CentralDirEntry     mCDE;
+};
+
+}; // namespace android
+
+#endif // __LIBS_ZIPENTRY_H
diff --git a/build/tools/zipalign/ZipFile.cpp b/build/tools/zipalign/ZipFile.cpp
new file mode 100644 (file)
index 0000000..62c9383
--- /dev/null
@@ -0,0 +1,1297 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Access to Zip archives.
+//
+
+#define LOG_TAG "zip"
+
+#include <utils/ZipUtils.h>
+#include <utils/Log.h>
+
+#include "ZipFile.h"
+
+#include <zlib.h>
+#define DEF_MEM_LEVEL 8                // normally in zutil.h?
+
+#include <memory.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <assert.h>
+
+using namespace android;
+
+/*
+ * Some environments require the "b", some choke on it.
+ */
+#define FILE_OPEN_RO        "rb"
+#define FILE_OPEN_RW        "r+b"
+#define FILE_OPEN_RW_CREATE "w+b"
+
+/* should live somewhere else? */
+static status_t errnoToStatus(int err)
+{
+    if (err == ENOENT)
+        return NAME_NOT_FOUND;
+    else if (err == EACCES)
+        return PERMISSION_DENIED;
+    else
+        return UNKNOWN_ERROR;
+}
+
+/*
+ * Open a file and parse its guts.
+ */
+status_t ZipFile::open(const char* zipFileName, int flags)
+{
+    bool newArchive = false;
+
+    assert(mZipFp == NULL);     // no reopen
+
+    if ((flags & kOpenTruncate))
+        flags |= kOpenCreate;           // trunc implies create
+
+    if ((flags & kOpenReadOnly) && (flags & kOpenReadWrite))
+        return INVALID_OPERATION;       // not both
+    if (!((flags & kOpenReadOnly) || (flags & kOpenReadWrite)))
+        return INVALID_OPERATION;       // not neither
+    if ((flags & kOpenCreate) && !(flags & kOpenReadWrite))
+        return INVALID_OPERATION;       // create requires write
+
+    if (flags & kOpenTruncate) {
+        newArchive = true;
+    } else {
+        newArchive = (access(zipFileName, F_OK) != 0);
+        if (!(flags & kOpenCreate) && newArchive) {
+            /* not creating, must already exist */
+            LOGD("File %s does not exist", zipFileName);
+            return NAME_NOT_FOUND;
+        }
+    }
+
+    /* open the file */
+    const char* openflags;
+    if (flags & kOpenReadWrite) {
+        if (newArchive)
+            openflags = FILE_OPEN_RW_CREATE;
+        else
+            openflags = FILE_OPEN_RW;
+    } else {
+        openflags = FILE_OPEN_RO;
+    }
+    mZipFp = fopen(zipFileName, openflags);
+    if (mZipFp == NULL) {
+        int err = errno;
+        LOGD("fopen failed: %d\n", err);
+        return errnoToStatus(err);
+    }
+
+    status_t result;
+    if (!newArchive) {
+        /*
+         * Load the central directory.  If that fails, then this probably
+         * isn't a Zip archive.
+         */
+        result = readCentralDir();
+    } else {
+        /*
+         * Newly-created.  The EndOfCentralDir constructor actually
+         * sets everything to be the way we want it (all zeroes).  We
+         * set mNeedCDRewrite so that we create *something* if the
+         * caller doesn't add any files.  (We could also just unlink
+         * the file if it's brand new and nothing was added, but that's
+         * probably doing more than we really should -- the user might
+         * have a need for empty zip files.)
+         */
+        mNeedCDRewrite = true;
+        result = NO_ERROR;
+    }
+
+    if (flags & kOpenReadOnly)
+        mReadOnly = true;
+    else
+        assert(!mReadOnly);
+
+    return result;
+}
+
+/*
+ * Return the Nth entry in the archive.
+ */
+ZipEntry* ZipFile::getEntryByIndex(int idx) const
+{
+    if (idx < 0 || idx >= (int) mEntries.size())
+        return NULL;
+
+    return mEntries[idx];
+}
+
+/*
+ * Find an entry by name.
+ */
+ZipEntry* ZipFile::getEntryByName(const char* fileName) const
+{
+    /*
+     * Do a stupid linear string-compare search.
+     *
+     * There are various ways to speed this up, especially since it's rare
+     * to intermingle changes to the archive with "get by name" calls.  We
+     * don't want to sort the mEntries vector itself, however, because
+     * it's used to recreate the Central Directory.
+     *
+     * (Hash table works, parallel list of pointers in sorted order is good.)
+     */
+    int idx;
+
+    for (idx = mEntries.size()-1; idx >= 0; idx--) {
+        ZipEntry* pEntry = mEntries[idx];
+        if (!pEntry->getDeleted() &&
+            strcmp(fileName, pEntry->getFileName()) == 0)
+        {
+            return pEntry;
+        }
+    }
+
+    return NULL;
+}
+
+/*
+ * Empty the mEntries vector.
+ */
+void ZipFile::discardEntries(void)
+{
+    int count = mEntries.size();
+
+    while (--count >= 0)
+        delete mEntries[count];
+
+    mEntries.clear();
+}
+
+
+/*
+ * Find the central directory and read the contents.
+ *
+ * The fun thing about ZIP archives is that they may or may not be
+ * readable from start to end.  In some cases, notably for archives
+ * that were written to stdout, the only length information is in the
+ * central directory at the end of the file.
+ *
+ * Of course, the central directory can be followed by a variable-length
+ * comment field, so we have to scan through it backwards.  The comment
+ * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff
+ * itself, plus apparently sometimes people throw random junk on the end
+ * just for the fun of it.
+ *
+ * This is all a little wobbly.  If the wrong value ends up in the EOCD
+ * area, we're hosed.  This appears to be the way that everbody handles
+ * it though, so we're in pretty good company if this fails.
+ */
+status_t ZipFile::readCentralDir(void)
+{
+    status_t result = NO_ERROR;
+    unsigned char* buf = NULL;
+    off_t fileLength, seekStart;
+    long readAmount;
+    int i;
+
+    fseek(mZipFp, 0, SEEK_END);
+    fileLength = ftell(mZipFp);
+    rewind(mZipFp);
+
+    /* too small to be a ZIP archive? */
+    if (fileLength < EndOfCentralDir::kEOCDLen) {
+        LOGD("Length is %ld -- too small\n", (long)fileLength);
+        result = INVALID_OPERATION;
+        goto bail;
+    }
+
+    buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch];
+    if (buf == NULL) {
+        LOGD("Failure allocating %d bytes for EOCD search",
+             EndOfCentralDir::kMaxEOCDSearch);
+        result = NO_MEMORY;
+        goto bail;
+    }
+
+    if (fileLength > EndOfCentralDir::kMaxEOCDSearch) {
+        seekStart = fileLength - EndOfCentralDir::kMaxEOCDSearch;
+        readAmount = EndOfCentralDir::kMaxEOCDSearch;
+    } else {
+        seekStart = 0;
+        readAmount = (long) fileLength;
+    }
+    if (fseek(mZipFp, seekStart, SEEK_SET) != 0) {
+        LOGD("Failure seeking to end of zip at %ld", (long) seekStart);
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    /* read the last part of the file into the buffer */
+    if (fread(buf, 1, readAmount, mZipFp) != (size_t) readAmount) {
+        LOGD("short file? wanted %ld\n", readAmount);
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    /* find the end-of-central-dir magic */
+    for (i = readAmount - 4; i >= 0; i--) {
+        if (buf[i] == 0x50 &&
+            ZipEntry::getLongLE(&buf[i]) == EndOfCentralDir::kSignature)
+        {
+            LOGV("+++ Found EOCD at buf+%d\n", i);
+            break;
+        }
+    }
+    if (i < 0) {
+        LOGD("EOCD not found, not Zip\n");
+        result = INVALID_OPERATION;
+        goto bail;
+    }
+
+    /* extract eocd values */
+    result = mEOCD.readBuf(buf + i, readAmount - i);
+    if (result != NO_ERROR) {
+        LOGD("Failure reading %ld bytes of EOCD values", readAmount - i);
+        goto bail;
+    }
+    //mEOCD.dump();
+
+    if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 ||
+        mEOCD.mNumEntries != mEOCD.mTotalNumEntries)
+    {
+        LOGD("Archive spanning not supported\n");
+        result = INVALID_OPERATION;
+        goto bail;
+    }
+
+    /*
+     * So far so good.  "mCentralDirSize" is the size in bytes of the
+     * central directory, so we can just seek back that far to find it.
+     * We can also seek forward mCentralDirOffset bytes from the
+     * start of the file.
+     *
+     * We're not guaranteed to have the rest of the central dir in the
+     * buffer, nor are we guaranteed that the central dir will have any
+     * sort of convenient size.  We need to skip to the start of it and
+     * read the header, then the other goodies.
+     *
+     * The only thing we really need right now is the file comment, which
+     * we're hoping to preserve.
+     */
+    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+        LOGD("Failure seeking to central dir offset %ld\n",
+             mEOCD.mCentralDirOffset);
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    /*
+     * Loop through and read the central dir entries.
+     */
+    LOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries);
+    int entry;
+    for (entry = 0; entry < mEOCD.mTotalNumEntries; entry++) {
+        ZipEntry* pEntry = new ZipEntry;
+
+        result = pEntry->initFromCDE(mZipFp);
+        if (result != NO_ERROR) {
+            LOGD("initFromCDE failed\n");
+            delete pEntry;
+            goto bail;
+        }
+
+        mEntries.add(pEntry);
+    }
+
+
+    /*
+     * If all went well, we should now be back at the EOCD.
+     */
+    {
+        unsigned char checkBuf[4];
+        if (fread(checkBuf, 1, 4, mZipFp) != 4) {
+            LOGD("EOCD check read failed\n");
+            result = INVALID_OPERATION;
+            goto bail;
+        }
+        if (ZipEntry::getLongLE(checkBuf) != EndOfCentralDir::kSignature) {
+            LOGD("EOCD read check failed\n");
+            result = UNKNOWN_ERROR;
+            goto bail;
+        }
+        LOGV("+++ EOCD read check passed\n");
+    }
+
+bail:
+    delete[] buf;
+    return result;
+}
+
+
+/*
+ * Add a new file to the archive.
+ *
+ * This requires creating and populating a ZipEntry structure, and copying
+ * the data into the file at the appropriate position.  The "appropriate
+ * position" is the current location of the central directory, which we
+ * casually overwrite (we can put it back later).
+ *
+ * If we were concerned about safety, we would want to make all changes
+ * in a temp file and then overwrite the original after everything was
+ * safely written.  Not really a concern for us.
+ */
+status_t ZipFile::addCommon(const char* fileName, const void* data, size_t size,
+    const char* storageName, int sourceType, int compressionMethod,
+    ZipEntry** ppEntry)
+{
+    ZipEntry* pEntry = NULL;
+    status_t result = NO_ERROR;
+    long lfhPosn, startPosn, endPosn, uncompressedLen;
+    FILE* inputFp = NULL;
+    unsigned long crc;
+    time_t modWhen;
+
+    if (mReadOnly)
+        return INVALID_OPERATION;
+
+    assert(compressionMethod == ZipEntry::kCompressDeflated ||
+           compressionMethod == ZipEntry::kCompressStored);
+
+    /* make sure we're in a reasonable state */
+    assert(mZipFp != NULL);
+    assert(mEntries.size() == mEOCD.mTotalNumEntries);
+
+    /* make sure it doesn't already exist */
+    if (getEntryByName(storageName) != NULL)
+        return ALREADY_EXISTS;
+
+    if (!data) {
+        inputFp = fopen(fileName, FILE_OPEN_RO);
+        if (inputFp == NULL)
+            return errnoToStatus(errno);
+    }
+
+    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    pEntry = new ZipEntry;
+    pEntry->initNew(storageName, NULL);
+
+    /*
+     * From here on out, failures are more interesting.
+     */
+    mNeedCDRewrite = true;
+
+    /*
+     * Write the LFH, even though it's still mostly blank.  We need it
+     * as a place-holder.  In theory the LFH isn't necessary, but in
+     * practice some utilities demand it.
+     */
+    lfhPosn = ftell(mZipFp);
+    pEntry->mLFH.write(mZipFp);
+    startPosn = ftell(mZipFp);
+
+    /*
+     * Copy the data in, possibly compressing it as we go.
+     */
+    if (sourceType == ZipEntry::kCompressStored) {
+        if (compressionMethod == ZipEntry::kCompressDeflated) {
+            bool failed = false;
+            result = compressFpToFp(mZipFp, inputFp, data, size, &crc);
+            if (result != NO_ERROR) {
+                LOGD("compression failed, storing\n");
+                failed = true;
+            } else {
+                /*
+                 * Make sure it has compressed "enough".  This probably ought
+                 * to be set through an API call, but I don't expect our
+                 * criteria to change over time.
+                 */
+                long src = inputFp ? ftell(inputFp) : size;
+                long dst = ftell(mZipFp) - startPosn;
+                if (dst + (dst / 10) > src) {
+                    LOGD("insufficient compression (src=%ld dst=%ld), storing\n",
+                        src, dst);
+                    failed = true;
+                }
+            }
+
+            if (failed) {
+                compressionMethod = ZipEntry::kCompressStored;
+                if (inputFp) rewind(inputFp);
+                fseek(mZipFp, startPosn, SEEK_SET);
+                /* fall through to kCompressStored case */
+            }
+        }
+        /* handle "no compression" request, or failed compression from above */
+        if (compressionMethod == ZipEntry::kCompressStored) {
+            if (inputFp) {
+                result = copyFpToFp(mZipFp, inputFp, &crc);
+            } else {
+                result = copyDataToFp(mZipFp, data, size, &crc);
+            }
+            if (result != NO_ERROR) {
+                // don't need to truncate; happens in CDE rewrite
+                LOGD("failed copying data in\n");
+                goto bail;
+            }
+        }
+
+        // currently seeked to end of file
+        uncompressedLen = inputFp ? ftell(inputFp) : size;
+    } else if (sourceType == ZipEntry::kCompressDeflated) {
+        /* we should support uncompressed-from-compressed, but it's not
+         * important right now */
+        assert(compressionMethod == ZipEntry::kCompressDeflated);
+
+        bool scanResult;
+        int method;
+        long compressedLen;
+
+        scanResult = ZipUtils::examineGzip(inputFp, &method, &uncompressedLen,
+                        &compressedLen, &crc);
+        if (!scanResult || method != ZipEntry::kCompressDeflated) {
+            LOGD("this isn't a deflated gzip file?");
+            result = UNKNOWN_ERROR;
+            goto bail;
+        }
+
+        result = copyPartialFpToFp(mZipFp, inputFp, compressedLen, NULL);
+        if (result != NO_ERROR) {
+            LOGD("failed copying gzip data in\n");
+            goto bail;
+        }
+    } else {
+        assert(false);
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    /*
+     * We could write the "Data Descriptor", but there doesn't seem to
+     * be any point since we're going to go back and write the LFH.
+     *
+     * Update file offsets.
+     */
+    endPosn = ftell(mZipFp);            // seeked to end of compressed data
+
+    /*
+     * Success!  Fill out new values.
+     */
+    pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc,
+        compressionMethod);
+    modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp));
+    pEntry->setModWhen(modWhen);
+    pEntry->setLFHOffset(lfhPosn);
+    mEOCD.mNumEntries++;
+    mEOCD.mTotalNumEntries++;
+    mEOCD.mCentralDirSize = 0;      // mark invalid; set by flush()
+    mEOCD.mCentralDirOffset = endPosn;
+
+    /*
+     * Go back and write the LFH.
+     */
+    if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) {
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+    pEntry->mLFH.write(mZipFp);
+
+    /*
+     * Add pEntry to the list.
+     */
+    mEntries.add(pEntry);
+    if (ppEntry != NULL)
+        *ppEntry = pEntry;
+    pEntry = NULL;
+
+bail:
+    if (inputFp != NULL)
+        fclose(inputFp);
+    delete pEntry;
+    return result;
+}
+
+/*
+ * Add an entry by copying it from another zip file.  If "padding" is
+ * nonzero, the specified number of bytes will be added to the "extra"
+ * field in the header.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
+    int padding, ZipEntry** ppEntry)
+{
+    ZipEntry* pEntry = NULL;
+    status_t result;
+    long lfhPosn, endPosn;
+
+    if (mReadOnly)
+        return INVALID_OPERATION;
+
+    /* make sure we're in a reasonable state */
+    assert(mZipFp != NULL);
+    assert(mEntries.size() == mEOCD.mTotalNumEntries);
+
+    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    pEntry = new ZipEntry;
+    if (pEntry == NULL) {
+        result = NO_MEMORY;
+        goto bail;
+    }
+
+    result = pEntry->initFromExternal(pSourceZip, pSourceEntry);
+    if (result != NO_ERROR)
+        goto bail;
+    if (padding != 0) {
+        result = pEntry->addPadding(padding);
+        if (result != NO_ERROR)
+            goto bail;
+    }
+
+    /*
+     * From here on out, failures are more interesting.
+     */
+    mNeedCDRewrite = true;
+
+    /*
+     * Write the LFH.  Since we're not recompressing the data, we already
+     * have all of the fields filled out.
+     */
+    lfhPosn = ftell(mZipFp);
+    pEntry->mLFH.write(mZipFp);
+
+    /*
+     * Copy the data over.
+     *
+     * If the "has data descriptor" flag is set, we want to copy the DD
+     * fields as well.  This is a fixed-size area immediately following
+     * the data.
+     */
+    if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0)
+    {
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    off_t copyLen;
+    copyLen = pSourceEntry->getCompressedLen();
+    if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0)
+        copyLen += ZipEntry::kDataDescriptorLen;
+
+    if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL)
+        != NO_ERROR)
+    {
+        LOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName);
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    /*
+     * Update file offsets.
+     */
+    endPosn = ftell(mZipFp);
+
+    /*
+     * Success!  Fill out new values.
+     */
+    pEntry->setLFHOffset(lfhPosn);      // sets mCDE.mLocalHeaderRelOffset
+    mEOCD.mNumEntries++;
+    mEOCD.mTotalNumEntries++;
+    mEOCD.mCentralDirSize = 0;      // mark invalid; set by flush()
+    mEOCD.mCentralDirOffset = endPosn;
+
+    /*
+     * Add pEntry to the list.
+     */
+    mEntries.add(pEntry);
+    if (ppEntry != NULL)
+        *ppEntry = pEntry;
+    pEntry = NULL;
+
+    result = NO_ERROR;
+
+bail:
+    delete pEntry;
+    return result;
+}
+
+/*
+ * Copy all of the bytes in "src" to "dst".
+ *
+ * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
+ * will be seeked immediately past the data.
+ */
+status_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32)
+{
+    unsigned char tmpBuf[32768];
+    size_t count;
+
+    *pCRC32 = crc32(0L, Z_NULL, 0);
+
+    while (1) {
+        count = fread(tmpBuf, 1, sizeof(tmpBuf), srcFp);
+        if (ferror(srcFp) || ferror(dstFp))
+            return errnoToStatus(errno);
+        if (count == 0)
+            break;
+
+        *pCRC32 = crc32(*pCRC32, tmpBuf, count);
+
+        if (fwrite(tmpBuf, 1, count, dstFp) != count) {
+            LOGD("fwrite %d bytes failed\n", (int) count);
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+/*
+ * Copy all of the bytes in "src" to "dst".
+ *
+ * On exit, "dstFp" will be seeked immediately past the data.
+ */
+status_t ZipFile::copyDataToFp(FILE* dstFp,
+    const void* data, size_t size, unsigned long* pCRC32)
+{
+    size_t count;
+
+    *pCRC32 = crc32(0L, Z_NULL, 0);
+    if (size > 0) {
+        *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size);
+        if (fwrite(data, 1, size, dstFp) != size) {
+            LOGD("fwrite %d bytes failed\n", (int) size);
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+/*
+ * Copy some of the bytes in "src" to "dst".
+ *
+ * If "pCRC32" is NULL, the CRC will not be computed.
+ *
+ * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
+ * will be seeked immediately past the data just written.
+ */
+status_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
+    unsigned long* pCRC32)
+{
+    unsigned char tmpBuf[32768];
+    size_t count;
+
+    if (pCRC32 != NULL)
+        *pCRC32 = crc32(0L, Z_NULL, 0);
+
+    while (length) {
+        long readSize;
+        
+        readSize = sizeof(tmpBuf);
+        if (readSize > length)
+            readSize = length;
+
+        count = fread(tmpBuf, 1, readSize, srcFp);
+        if ((long) count != readSize) {     // error or unexpected EOF
+            LOGD("fread %d bytes failed\n", (int) readSize);
+            return UNKNOWN_ERROR;
+        }
+
+        if (pCRC32 != NULL)
+            *pCRC32 = crc32(*pCRC32, tmpBuf, count);
+
+        if (fwrite(tmpBuf, 1, count, dstFp) != count) {
+            LOGD("fwrite %d bytes failed\n", (int) count);
+            return UNKNOWN_ERROR;
+        }
+
+        length -= readSize;
+    }
+
+    return NO_ERROR;
+}
+
+/*
+ * Compress all of the data in "srcFp" and write it to "dstFp".
+ *
+ * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
+ * will be seeked immediately past the compressed data.
+ */
+status_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp,
+    const void* data, size_t size, unsigned long* pCRC32)
+{
+    status_t result = NO_ERROR;
+    const size_t kBufSize = 32768;
+    unsigned char* inBuf = NULL;
+    unsigned char* outBuf = NULL;
+    z_stream zstream;
+    bool atEof = false;     // no feof() aviailable yet
+    unsigned long crc;
+    int zerr;
+
+    /*
+     * Create an input buffer and an output buffer.
+     */
+    inBuf = new unsigned char[kBufSize];
+    outBuf = new unsigned char[kBufSize];
+    if (inBuf == NULL || outBuf == NULL) {
+        result = NO_MEMORY;
+        goto bail;
+    }
+
+    /*
+     * Initialize the zlib stream.
+     */
+    memset(&zstream, 0, sizeof(zstream));
+    zstream.zalloc = Z_NULL;
+    zstream.zfree = Z_NULL;
+    zstream.opaque = Z_NULL;
+    zstream.next_in = NULL;
+    zstream.avail_in = 0;
+    zstream.next_out = outBuf;
+    zstream.avail_out = kBufSize;
+    zstream.data_type = Z_UNKNOWN;
+
+    zerr = deflateInit2(&zstream, Z_BEST_COMPRESSION,
+        Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+    if (zerr != Z_OK) {
+        result = UNKNOWN_ERROR;
+        if (zerr == Z_VERSION_ERROR) {
+            LOGE("Installed zlib is not compatible with linked version (%s)\n",
+                ZLIB_VERSION);
+        } else {
+            LOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr);
+        }
+        goto bail;
+    }
+
+    crc = crc32(0L, Z_NULL, 0);
+
+    /*
+     * Loop while we have data.
+     */
+    do {
+        size_t getSize;
+        int flush;
+
+        /* only read if the input buffer is empty */
+        if (zstream.avail_in == 0 && !atEof) {
+            LOGV("+++ reading %d bytes\n", (int)kBufSize);
+            if (data) {
+                getSize = size > kBufSize ? kBufSize : size;
+                memcpy(inBuf, data, getSize);
+                data = ((const char*)data) + getSize;
+                size -= getSize;
+            } else {
+                getSize = fread(inBuf, 1, kBufSize, srcFp);
+                if (ferror(srcFp)) {
+                    LOGD("deflate read failed (errno=%d)\n", errno);
+                    goto z_bail;
+                }
+            }
+            if (getSize < kBufSize) {
+                LOGV("+++  got %d bytes, EOF reached\n",
+                    (int)getSize);
+                atEof = true;
+            }
+
+            crc = crc32(crc, inBuf, getSize);
+
+            zstream.next_in = inBuf;
+            zstream.avail_in = getSize;
+        }
+
+        if (atEof)
+            flush = Z_FINISH;       /* tell zlib that we're done */
+        else
+            flush = Z_NO_FLUSH;     /* more to come! */
+
+        zerr = deflate(&zstream, flush);
+        if (zerr != Z_OK && zerr != Z_STREAM_END) {
+            LOGD("zlib deflate call failed (zerr=%d)\n", zerr);
+            result = UNKNOWN_ERROR;
+            goto z_bail;
+        }
+
+        /* write when we're full or when we're done */
+        if (zstream.avail_out == 0 ||
+            (zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize))
+        {
+            LOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf));
+            if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) !=
+                (size_t)(zstream.next_out - outBuf))
+            {
+                LOGD("write %d failed in deflate\n",
+                    (int) (zstream.next_out - outBuf));
+                goto z_bail;
+            }
+
+            zstream.next_out = outBuf;
+            zstream.avail_out = kBufSize;
+        }
+    } while (zerr == Z_OK);
+
+    assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
+
+    *pCRC32 = crc;
+
+z_bail:
+    deflateEnd(&zstream);        /* free up any allocated structures */
+
+bail:
+    delete[] inBuf;
+    delete[] outBuf;
+
+    return result;
+}
+
+/*
+ * Mark an entry as deleted.
+ *
+ * We will eventually need to crunch the file down, but if several files
+ * are being removed (perhaps as part of an "update" process) we can make
+ * things considerably faster by deferring the removal to "flush" time.
+ */
+status_t ZipFile::remove(ZipEntry* pEntry)
+{
+    /*
+     * Should verify that pEntry is actually part of this archive, and
+     * not some stray ZipEntry from a different file.
+     */
+
+    /* mark entry as deleted, and mark archive as dirty */
+    pEntry->setDeleted();
+    mNeedCDRewrite = true;
+    return NO_ERROR;
+}
+
+/*
+ * Flush any pending writes.
+ *
+ * In particular, this will crunch out deleted entries, and write the
+ * Central Directory and EOCD if we have stomped on them.
+ */
+status_t ZipFile::flush(void)
+{
+    status_t result = NO_ERROR;
+    long eocdPosn;
+    int i, count;
+
+    if (mReadOnly)
+        return INVALID_OPERATION;
+    if (!mNeedCDRewrite)
+        return NO_ERROR;
+
+    assert(mZipFp != NULL);
+
+    result = crunchArchive();
+    if (result != NO_ERROR)
+        return result;
+
+    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0)
+        return UNKNOWN_ERROR;
+
+    count = mEntries.size();
+    for (i = 0; i < count; i++) {
+        ZipEntry* pEntry = mEntries[i];
+        pEntry->mCDE.write(mZipFp);
+    }
+
+    eocdPosn = ftell(mZipFp);
+    mEOCD.mCentralDirSize = eocdPosn - mEOCD.mCentralDirOffset;
+
+    mEOCD.write(mZipFp);
+
+    /*
+     * If we had some stuff bloat up during compression and get replaced
+     * with plain files, or if we deleted some entries, there's a lot
+     * of wasted space at the end of the file.  Remove it now.
+     */
+    if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) {
+        LOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno));
+        // not fatal
+    }
+
+    /* should we clear the "newly added" flag in all entries now? */
+
+    mNeedCDRewrite = false;
+    return NO_ERROR;
+}
+
+/*
+ * Crunch deleted files out of an archive by shifting the later files down.
+ *
+ * Because we're not using a temp file, we do the operation inside the
+ * current file.
+ */
+status_t ZipFile::crunchArchive(void)
+{
+    status_t result = NO_ERROR;
+    int i, count;
+    long delCount, adjust;
+
+#if 0
+    printf("CONTENTS:\n");
+    for (i = 0; i < (int) mEntries.size(); i++) {
+        printf(" %d: lfhOff=%ld del=%d\n",
+            i, mEntries[i]->getLFHOffset(), mEntries[i]->getDeleted());
+    }
+    printf("  END is %ld\n", (long) mEOCD.mCentralDirOffset);
+#endif
+
+    /*
+     * Roll through the set of files, shifting them as appropriate.  We
+     * could probably get a slight performance improvement by sliding
+     * multiple files down at once (because we could use larger reads
+     * when operating on batches of small files), but it's not that useful.
+     */
+    count = mEntries.size();
+    delCount = adjust = 0;
+    for (i = 0; i < count; i++) {
+        ZipEntry* pEntry = mEntries[i];
+        long span;
+
+        if (pEntry->getLFHOffset() != 0) {
+            long nextOffset;
+
+            /* Get the length of this entry by finding the offset
+             * of the next entry.  Directory entries don't have
+             * file offsets, so we need to find the next non-directory
+             * entry.
+             */
+            nextOffset = 0;
+            for (int ii = i+1; nextOffset == 0 && ii < count; ii++)
+                nextOffset = mEntries[ii]->getLFHOffset();
+            if (nextOffset == 0)
+                nextOffset = mEOCD.mCentralDirOffset;
+            span = nextOffset - pEntry->getLFHOffset();
+
+            assert(span >= ZipEntry::LocalFileHeader::kLFHLen);
+        } else {
+            /* This is a directory entry.  It doesn't have
+             * any actual file contents, so there's no need to
+             * move anything.
+             */
+            span = 0;
+        }
+
+        //printf("+++ %d: off=%ld span=%ld del=%d [count=%d]\n",
+        //    i, pEntry->getLFHOffset(), span, pEntry->getDeleted(), count);
+
+        if (pEntry->getDeleted()) {
+            adjust += span;
+            delCount++;
+
+            delete pEntry;
+            mEntries.removeAt(i);
+
+            /* adjust loop control */
+            count--;
+            i--;
+        } else if (span != 0 && adjust > 0) {
+            /* shuffle this entry back */
+            //printf("+++ Shuffling '%s' back %ld\n",
+            //    pEntry->getFileName(), adjust);
+            result = filemove(mZipFp, pEntry->getLFHOffset() - adjust,
+                        pEntry->getLFHOffset(), span);
+            if (result != NO_ERROR) {
+                /* this is why you use a temp file */
+                LOGE("error during crunch - archive is toast\n");
+                return result;
+            }
+
+            pEntry->setLFHOffset(pEntry->getLFHOffset() - adjust);
+        }
+    }
+
+    /*
+     * Fix EOCD info.  We have to wait until the end to do some of this
+     * because we use mCentralDirOffset to determine "span" for the
+     * last entry.
+     */
+    mEOCD.mCentralDirOffset -= adjust;
+    mEOCD.mNumEntries -= delCount;
+    mEOCD.mTotalNumEntries -= delCount;
+    mEOCD.mCentralDirSize = 0;  // mark invalid; set by flush()
+
+    assert(mEOCD.mNumEntries == mEOCD.mTotalNumEntries);
+    assert(mEOCD.mNumEntries == count);
+
+    return result;
+}
+
+/*
+ * Works like memmove(), but on pieces of a file.
+ */
+status_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n)
+{
+    if (dst == src || n <= 0)
+        return NO_ERROR;
+
+    unsigned char readBuf[32768];
+
+    if (dst < src) {
+        /* shift stuff toward start of file; must read from start */
+        while (n != 0) {
+            size_t getSize = sizeof(readBuf);
+            if (getSize > n)
+                getSize = n;
+
+            if (fseek(fp, (long) src, SEEK_SET) != 0) {
+                LOGD("filemove src seek %ld failed\n", (long) src);
+                return UNKNOWN_ERROR;
+            }
+
+            if (fread(readBuf, 1, getSize, fp) != getSize) {
+                LOGD("filemove read %ld off=%ld failed\n",
+                    (long) getSize, (long) src);
+                return UNKNOWN_ERROR;
+            }
+
+            if (fseek(fp, (long) dst, SEEK_SET) != 0) {
+                LOGD("filemove dst seek %ld failed\n", (long) dst);
+                return UNKNOWN_ERROR;
+            }
+
+            if (fwrite(readBuf, 1, getSize, fp) != getSize) {
+                LOGD("filemove write %ld off=%ld failed\n",
+                    (long) getSize, (long) dst);
+                return UNKNOWN_ERROR;
+            }
+
+            src += getSize;
+            dst += getSize;
+            n -= getSize;
+        }
+    } else {
+        /* shift stuff toward end of file; must read from end */
+        assert(false);      // write this someday, maybe
+        return UNKNOWN_ERROR;
+    }
+
+    return NO_ERROR;
+}
+
+
+/*
+ * Get the modification time from a file descriptor.
+ */
+time_t ZipFile::getModTime(int fd)
+{
+    struct stat sb;
+
+    if (fstat(fd, &sb) < 0) {
+        LOGD("HEY: fstat on fd %d failed\n", fd);
+        return (time_t) -1;
+    }
+
+    return sb.st_mtime;
+}
+
+
+#if 0       /* this is a bad idea */
+/*
+ * Get a copy of the Zip file descriptor.
+ *
+ * We don't allow this if the file was opened read-write because we tend
+ * to leave the file contents in an uncertain state between calls to
+ * flush().  The duplicated file descriptor should only be valid for reads.
+ */
+int ZipFile::getZipFd(void) const
+{
+    if (!mReadOnly)
+        return INVALID_OPERATION;
+    assert(mZipFp != NULL);
+
+    int fd;
+    fd = dup(fileno(mZipFp));
+    if (fd < 0) {
+        LOGD("didn't work, errno=%d\n", errno);
+    }
+
+    return fd;
+}
+#endif
+
+
+#if 0
+/*
+ * Expand data.
+ */
+bool ZipFile::uncompress(const ZipEntry* pEntry, void* buf) const
+{
+    return false;
+}
+#endif
+
+// free the memory when you're done
+void* ZipFile::uncompress(const ZipEntry* entry)
+{
+    size_t unlen = entry->getUncompressedLen();
+    size_t clen = entry->getCompressedLen();
+
+    void* buf = malloc(unlen);
+    if (buf == NULL) {
+        return NULL;
+    }
+
+    fseek(mZipFp, 0, SEEK_SET);
+
+    off_t offset = entry->getFileOffset();
+    if (fseek(mZipFp, offset, SEEK_SET) != 0) {
+        goto bail;
+    }
+
+    switch (entry->getCompressionMethod())
+    {
+        case ZipEntry::kCompressStored: {
+            ssize_t amt = fread(buf, 1, unlen, mZipFp);
+            if (amt != (ssize_t)unlen) {
+                goto bail;
+            }
+#if 0
+            printf("data...\n");
+            const unsigned char* p = (unsigned char*)buf;
+            const unsigned char* end = p+unlen;
+            for (int i=0; i<32 && p < end; i++) {
+                printf("0x%08x ", (int)(offset+(i*0x10)));
+                for (int j=0; j<0x10 && p < end; j++) {
+                    printf(" %02x", *p);
+                    p++;
+                }
+                printf("\n");
+            }
+#endif
+
+            }
+            break;
+        case ZipEntry::kCompressDeflated: {
+            if (!ZipUtils::inflateToBuffer(mZipFp, buf, unlen, clen)) {
+                goto bail;
+            }
+            }
+            break;
+        default:
+            goto bail;
+    }
+    return buf;
+
+bail:
+    free(buf);
+    return NULL;
+}
+
+
+/*
+ * ===========================================================================
+ *      ZipFile::EndOfCentralDir
+ * ===========================================================================
+ */
+
+/*
+ * Read the end-of-central-dir fields.
+ *
+ * "buf" should be positioned at the EOCD signature, and should contain
+ * the entire EOCD area including the comment.
+ */
+status_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len)
+{
+    /* don't allow re-use */
+    assert(mComment == NULL);
+
+    if (len < kEOCDLen) {
+        /* looks like ZIP file got truncated */
+        LOGD(" Zip EOCD: expected >= %d bytes, found %d\n",
+            kEOCDLen, len);
+        return INVALID_OPERATION;
+    }
+
+    /* this should probably be an assert() */
+    if (ZipEntry::getLongLE(&buf[0x00]) != kSignature)
+        return UNKNOWN_ERROR;
+
+    mDiskNumber = ZipEntry::getShortLE(&buf[0x04]);
+    mDiskWithCentralDir = ZipEntry::getShortLE(&buf[0x06]);
+    mNumEntries = ZipEntry::getShortLE(&buf[0x08]);
+    mTotalNumEntries = ZipEntry::getShortLE(&buf[0x0a]);
+    mCentralDirSize = ZipEntry::getLongLE(&buf[0x0c]);
+    mCentralDirOffset = ZipEntry::getLongLE(&buf[0x10]);
+    mCommentLen = ZipEntry::getShortLE(&buf[0x14]);
+
+    // TODO: validate mCentralDirOffset
+
+    if (mCommentLen > 0) {
+        if (kEOCDLen + mCommentLen > len) {
+            LOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n",
+                kEOCDLen, mCommentLen, len);
+            return UNKNOWN_ERROR;
+        }
+        mComment = new unsigned char[mCommentLen];
+        memcpy(mComment, buf + kEOCDLen, mCommentLen);
+    }
+
+    return NO_ERROR;
+}
+
+/*
+ * Write an end-of-central-directory section.
+ */
+status_t ZipFile::EndOfCentralDir::write(FILE* fp)
+{
+    unsigned char buf[kEOCDLen];
+
+    ZipEntry::putLongLE(&buf[0x00], kSignature);
+    ZipEntry::putShortLE(&buf[0x04], mDiskNumber);
+    ZipEntry::putShortLE(&buf[0x06], mDiskWithCentralDir);
+    ZipEntry::putShortLE(&buf[0x08], mNumEntries);
+    ZipEntry::putShortLE(&buf[0x0a], mTotalNumEntries);
+    ZipEntry::putLongLE(&buf[0x0c], mCentralDirSize);
+    ZipEntry::putLongLE(&buf[0x10], mCentralDirOffset);
+    ZipEntry::putShortLE(&buf[0x14], mCommentLen);
+
+    if (fwrite(buf, 1, kEOCDLen, fp) != kEOCDLen)
+        return UNKNOWN_ERROR;
+    if (mCommentLen > 0) {
+        assert(mComment != NULL);
+        if (fwrite(mComment, mCommentLen, 1, fp) != mCommentLen)
+            return UNKNOWN_ERROR;
+    }
+
+    return NO_ERROR;
+}
+
+/*
+ * Dump the contents of an EndOfCentralDir object.
+ */
+void ZipFile::EndOfCentralDir::dump(void) const
+{
+    LOGD(" EndOfCentralDir contents:\n");
+    LOGD("  diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n",
+        mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries);
+    LOGD("  centDirSize=%lu centDirOff=%lu commentLen=%u\n",
+        mCentralDirSize, mCentralDirOffset, mCommentLen);
+}
+
diff --git a/build/tools/zipalign/ZipFile.h b/build/tools/zipalign/ZipFile.h
new file mode 100644 (file)
index 0000000..dbbd072
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// General-purpose Zip archive access.  This class allows both reading and
+// writing to Zip archives, including deletion of existing entries.
+//
+#ifndef __LIBS_ZIPFILE_H
+#define __LIBS_ZIPFILE_H
+
+#include <utils/Vector.h>
+#include <utils/Errors.h>
+#include <stdio.h>
+
+#include "ZipEntry.h"
+
+namespace android {
+
+/*
+ * Manipulate a Zip archive.
+ *
+ * Some changes will not be visible in the until until "flush" is called.
+ *
+ * The correct way to update a file archive is to make all changes to a
+ * copy of the archive in a temporary file, and then unlink/rename over
+ * the original after everything completes.  Because we're only interested
+ * in using this for packaging, we don't worry about such things.  Crashing
+ * after making changes and before flush() completes could leave us with
+ * an unusable Zip archive.
+ */
+class ZipFile {
+public:
+    ZipFile(void)
+      : mZipFp(NULL), mReadOnly(false), mNeedCDRewrite(false)
+      {}
+    ~ZipFile(void) {
+        if (!mReadOnly)
+            flush();
+        if (mZipFp != NULL)
+            fclose(mZipFp);
+        discardEntries();
+    }
+
+    /*
+     * Open a new or existing archive.
+     */
+    typedef enum {
+        kOpenReadOnly   = 0x01,
+        kOpenReadWrite  = 0x02,
+        kOpenCreate     = 0x04,     // create if it doesn't exist
+        kOpenTruncate   = 0x08,     // if it exists, empty it
+    };
+    status_t open(const char* zipFileName, int flags);
+
+    /*
+     * Add a file to the end of the archive.  Specify whether you want the
+     * library to try to store it compressed.
+     *
+     * If "storageName" is specified, the archive will use that instead
+     * of "fileName".
+     *
+     * If there is already an entry with the same name, the call fails.
+     * Existing entries with the same name must be removed first.
+     *
+     * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+     */
+    status_t add(const char* fileName, int compressionMethod,
+        ZipEntry** ppEntry)
+    {
+        return add(fileName, fileName, compressionMethod, ppEntry);
+    }
+    status_t add(const char* fileName, const char* storageName,
+        int compressionMethod, ZipEntry** ppEntry)
+    {
+        return addCommon(fileName, NULL, 0, storageName,
+                         ZipEntry::kCompressStored,
+                         compressionMethod, ppEntry);
+    }
+
+    /*
+     * Add a file that is already compressed with gzip.
+     *
+     * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+     */
+    status_t addGzip(const char* fileName, const char* storageName,
+        ZipEntry** ppEntry)
+    {
+        return addCommon(fileName, NULL, 0, storageName,
+                         ZipEntry::kCompressDeflated,
+                         ZipEntry::kCompressDeflated, ppEntry);
+    }
+
+    /*
+     * Add a file from an in-memory data buffer.
+     *
+     * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+     */
+    status_t add(const void* data, size_t size, const char* storageName,
+        int compressionMethod, ZipEntry** ppEntry)
+    {
+        return addCommon(NULL, data, size, storageName,
+                         ZipEntry::kCompressStored,
+                         compressionMethod, ppEntry);
+    }
+
+    /*
+     * Add an entry by copying it from another zip file.  If "padding" is
+     * nonzero, the specified number of bytes will be added to the "extra"
+     * field in the header.
+     *
+     * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+     */
+    status_t add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
+        int padding, ZipEntry** ppEntry);
+
+    /*
+     * Mark an entry as having been removed.  It is not actually deleted
+     * from the archive or our internal data structures until flush() is
+     * called.
+     */
+    status_t remove(ZipEntry* pEntry);
+
+    /*
+     * Flush changes.  If mNeedCDRewrite is set, this writes the central dir.
+     */
+    status_t flush(void);
+
+    /*
+     * Expand the data into the buffer provided.  The buffer must hold
+     * at least <uncompressed len> bytes.  Variation expands directly
+     * to a file.
+     *
+     * Returns "false" if an error was encountered in the compressed data.
+     */
+    //bool uncompress(const ZipEntry* pEntry, void* buf) const;
+    //bool uncompress(const ZipEntry* pEntry, FILE* fp) const;
+    void* uncompress(const ZipEntry* pEntry);
+
+    /*
+     * Get an entry, by name.  Returns NULL if not found.
+     *
+     * Does not return entries pending deletion.
+     */
+    ZipEntry* getEntryByName(const char* fileName) const;
+
+    /*
+     * Get the Nth entry in the archive.
+     *
+     * This will return an entry that is pending deletion.
+     */
+    int getNumEntries(void) const { return mEntries.size(); }
+    ZipEntry* getEntryByIndex(int idx) const;
+
+private:
+    /* these are private and not defined */
+    ZipFile(const ZipFile& src);
+    ZipFile& operator=(const ZipFile& src);
+
+    class EndOfCentralDir {
+    public:
+        EndOfCentralDir(void) :
+            mDiskNumber(0),
+            mDiskWithCentralDir(0),
+            mNumEntries(0),
+            mTotalNumEntries(0),
+            mCentralDirSize(0),
+            mCentralDirOffset(0),
+            mCommentLen(0),
+            mComment(NULL)
+            {}
+        virtual ~EndOfCentralDir(void) {
+            delete[] mComment;
+        }
+
+        status_t readBuf(const unsigned char* buf, int len);
+        status_t write(FILE* fp);
+
+        //unsigned long   mSignature;
+        unsigned short  mDiskNumber;
+        unsigned short  mDiskWithCentralDir;
+        unsigned short  mNumEntries;
+        unsigned short  mTotalNumEntries;
+        unsigned long   mCentralDirSize;
+        unsigned long   mCentralDirOffset;      // offset from first disk
+        unsigned short  mCommentLen;
+        unsigned char*  mComment;
+
+        enum {
+            kSignature      = 0x06054b50,
+            kEOCDLen        = 22,       // EndOfCentralDir len, excl. comment
+
+            kMaxCommentLen  = 65535,    // longest possible in ushort
+            kMaxEOCDSearch  = kMaxCommentLen + EndOfCentralDir::kEOCDLen,
+
+        };
+
+        void dump(void) const;
+    };
+
+
+    /* read all entries in the central dir */
+    status_t readCentralDir(void);
+
+    /* crunch deleted entries out */
+    status_t crunchArchive(void);
+
+    /* clean up mEntries */
+    void discardEntries(void);
+
+    /* common handler for all "add" functions */
+    status_t addCommon(const char* fileName, const void* data, size_t size,
+        const char* storageName, int sourceType, int compressionMethod,
+        ZipEntry** ppEntry);
+
+    /* copy all of "srcFp" into "dstFp" */
+    status_t copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32);
+    /* copy all of "data" into "dstFp" */
+    status_t copyDataToFp(FILE* dstFp,
+        const void* data, size_t size, unsigned long* pCRC32);
+    /* copy some of "srcFp" into "dstFp" */
+    status_t copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
+        unsigned long* pCRC32);
+    /* like memmove(), but on parts of a single file */
+    status_t filemove(FILE* fp, off_t dest, off_t src, size_t n);
+    /* compress all of "srcFp" into "dstFp", using Deflate */
+    status_t compressFpToFp(FILE* dstFp, FILE* srcFp,
+        const void* data, size_t size, unsigned long* pCRC32);
+
+    /* get modification date from a file descriptor */
+    time_t getModTime(int fd);
+
+    /*
+     * We use stdio FILE*, which gives us buffering but makes dealing
+     * with files >2GB awkward.  Until we support Zip64, we're fine.
+     */
+    FILE*           mZipFp;             // Zip file pointer
+
+    /* one of these per file */
+    EndOfCentralDir mEOCD;
+
+    /* did we open this read-only? */
+    bool            mReadOnly;
+
+    /* set this when we trash the central dir */
+    bool            mNeedCDRewrite;
+
+    /*
+     * One ZipEntry per entry in the zip file.  I'm using pointers instead
+     * of objects because it's easier than making operator= work for the
+     * classes and sub-classes.
+     */
+    Vector<ZipEntry*>   mEntries;
+};
+
+}; // namespace android
+
+#endif // __LIBS_ZIPFILE_H