Implement path-based enabling of code coverage.

Native coverage is enabled by setting NATIVE_COVERAGE to true
and specifying a list of paths in the COVERAGE_PATHS
environment variable. Files are exported to a zip file in the
target out directory.

Change-Id: I66a2ddd88e849bec1cc0cdae1b51fe18a007e2c3
diff --git a/core/Makefile b/core/Makefile
index 4ed8947..1382026 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -2059,6 +2059,28 @@
 	$(hide) mkdir -p $(dir $@) $(TARGET_OUT_UNSTRIPPED) $(dir $(PRIVATE_LIST_FILE))
 	$(hide) find $(TARGET_OUT_UNSTRIPPED) | sort >$(PRIVATE_LIST_FILE)
 	$(hide) $(SOONG_ZIP) -d -o $@ -C . -l $(PRIVATE_LIST_FILE)
+# -----------------------------------------------------------------
+# A zip of the coverage directory.
+#
+name := $(TARGET_PRODUCT)
+ifeq ($(TARGET_BUILD_TYPE),debug)
+name := $(name)_debug
+endif
+name := $(name)-coverage-$(FILE_NAME_TAG)
+COVERAGE_ZIP := $(PRODUCT_OUT)/$(name).zip
+ifndef TARGET_BUILD_APPS
+$(COVERAGE_ZIP): $(INSTALLED_SYSTEMIMAGE) \
+		$(INSTALLED_BOOTIMAGE_TARGET) \
+		$(INSTALLED_USERDATAIMAGE_TARGET) \
+		$(INSTALLED_VENDORIMAGE_TARGET)
+endif
+$(COVERAGE_ZIP): PRIVATE_LIST_FILE := $(call intermediates-dir-for,PACKAGING,coverage)/filelist
+$(COVERAGE_ZIP): $(SOONG_ZIP)
+	@echo "Package coverage: $@"
+	$(hide) rm -rf $@ $(PRIVATE_LIST_FILE)
+	$(hide) mkdir -p $(dir $@) $(TARGET_OUT_COVERAGE) $(dir $(PRIVATE_LIST_FILE))
+	$(hide) find $(TARGET_OUT_COVERAGE) | sort >$(PRIVATE_LIST_FILE)
+	$(hide) $(SOONG_ZIP) -d -o $@ -C $(TARGET_OUT_COVERAGE) -l $(PRIVATE_LIST_FILE)
 
 # -----------------------------------------------------------------
 # A zip of the Android Apps. Not keeping full path so that we don't
@@ -2217,6 +2239,7 @@
 	$(tools_notice_file_txt) \
 	$(OUT_DOCS)/offline-sdk-timestamp \
 	$(SYMBOLS_ZIP) \
+	$(COVERAGE_ZIP) \
 	$(INSTALLED_SYSTEMIMAGE) \
 	$(INSTALLED_USERDATAIMAGE_TARGET) \
 	$(INSTALLED_RAMDISK_TARGET) \
diff --git a/core/binary.mk b/core/binary.mk
index 21a6019..3d51371 100644
--- a/core/binary.mk
+++ b/core/binary.mk
@@ -54,10 +54,15 @@
 my_cxx_wrapper := $(CXX_WRAPPER)
 my_c_includes := $(LOCAL_C_INCLUDES)
 my_generated_sources := $(LOCAL_GENERATED_SOURCES)
-my_native_coverage := $(LOCAL_NATIVE_COVERAGE)
 my_additional_dependencies := $(LOCAL_ADDITIONAL_DEPENDENCIES)
 my_export_c_include_dirs := $(LOCAL_EXPORT_C_INCLUDE_DIRS)
 
+ifneq (,$(foreach dir,$(COVERAGE_PATHS),$(filter $(dir)%,$(LOCAL_PATH))))
+  my_native_coverage := true
+else
+  my_native_coverage := false
+endif
+
 ifdef LOCAL_IS_HOST_MODULE
 my_allow_undefined_symbols := true
 else
@@ -1769,3 +1774,11 @@
     $(my_system_shared_libraries)
 SOONG_CONV := $(SOONG_CONV) $(LOCAL_MODULE)
 endif
+
+###########################################################
+# Coverage packaging.
+###########################################################
+ifeq ($(my_native_coverage),true)
+LOCAL_GCNO_FILES := $(patsubst %.o,%.gcno,$(all_objects))
+$(foreach f,$(all_objects),$(eval $(call gcno-touch-rule,$(f),$(f:.o=.gcno))))
+endif
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index 635dd55..5f7a705 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -191,7 +191,6 @@
 LOCAL_MODULE_UNSUPPORTED_HOST_CROSS_ARCH_WARN:=
 LOCAL_NO_FPIE :=
 LOCAL_CXX_STL := default
-LOCAL_NATIVE_COVERAGE :=
 LOCAL_DPI_VARIANTS:=
 LOCAL_DPI_FILE_STEM:=
 LOCAL_SANITIZE:=
@@ -236,6 +235,7 @@
 LOCAL_PREBUILT_JNI_LIBS_$(TARGET_ARCH):=
 LOCAL_STRIP_MODULE_$(TARGET_ARCH):=
 LOCAL_PACK_MODULE_RELOCATIONS_$(TARGET_ARCH):=
+LOCAL_GCNO_FILES:=
 ifdef TARGET_2ND_ARCH
 LOCAL_SRC_FILES_$(TARGET_2ND_ARCH):=
 LOCAL_SRC_FILES_EXCLUDE_$(TARGET_2ND_ARCH):=
diff --git a/core/definitions.mk b/core/definitions.mk
index 2c09910..0c169e4 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -123,6 +123,15 @@
 $(filter true, $(1))
 endef
 
+###########################################################
+## Rule for touching GCNO files.
+###########################################################
+define gcno-touch-rule
+$(2): $(1)
+	touch -c $$@
+endef
+
+###########################################################
 
 ###########################################################
 ## Retrieve the directory of the current makefile
diff --git a/core/envsetup.mk b/core/envsetup.mk
index a221fb9..39a754b 100644
--- a/core/envsetup.mk
+++ b/core/envsetup.mk
@@ -261,10 +261,12 @@
 HOST_OUT_JAVA_LIBRARIES := $(HOST_OUT)/framework
 HOST_OUT_SDK_ADDON := $(HOST_OUT)/sdk_addon
 HOST_OUT_NATIVE_TESTS := $(HOST_OUT)/nativetest64
+HOST_OUT_COVERAGE := $(HOST_OUT)/coverage
 
 HOST_CROSS_OUT_EXECUTABLES := $(HOST_CROSS_OUT)/bin
 HOST_CROSS_OUT_SHARED_LIBRARIES := $(HOST_CROSS_OUT)/lib
 HOST_CROSS_OUT_NATIVE_TESTS := $(HOST_CROSS_OUT)/nativetest
+HOST_CROSS_OUT_COVERAGE := $(HOST_CROSS_OUT)/coverage
 
 HOST_OUT_INTERMEDIATES := $(HOST_OUT)/obj
 HOST_OUT_HEADERS := $(HOST_OUT_INTERMEDIATES)/include
@@ -467,6 +469,7 @@
 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_OUT_COVERAGE := $(PRODUCT_OUT)/coverages
 
 TARGET_ROOT_OUT := $(PRODUCT_OUT)/$(TARGET_COPY_OUT_ROOT)
 TARGET_ROOT_OUT_BIN := $(TARGET_ROOT_OUT)/bin
diff --git a/core/main.mk b/core/main.mk
index d768ecb..8fc2a24 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -988,6 +988,9 @@
   $(SYMBOLS_ZIP) : $(apps_only_installed_files)
   $(call dist-for-goals,apps_only, $(SYMBOLS_ZIP))
 
+  $(COVERAGE_ZIP) : $(apps_only_installed_files)
+  $(call dist-for-goals,apps_only, $(COVERAGE_ZIP))
+
 .PHONY: apps_only
 apps_only: $(unbundled_build_modules)
 
@@ -1008,6 +1011,7 @@
     $(INTERNAL_OTA_PACKAGE_TARGET) \
     $(BUILT_OTATOOLS_PACKAGE) \
     $(SYMBOLS_ZIP) \
+    $(COVERAGE_ZIP) \
     $(INSTALLED_FILES_FILE) \
     $(INSTALLED_FILES_FILE_VENDOR) \
     $(INSTALLED_BUILD_PROP_TARGET) \
@@ -1050,6 +1054,7 @@
 $(call dist-for-goals,sdk win_sdk, \
     $(ALL_SDK_TARGETS) \
     $(SYMBOLS_ZIP) \
+    $(COVERAGE_ZIP) \
     $(INSTALLED_BUILD_PROP_TARGET) \
 )
 
diff --git a/core/prebuilt_internal.mk b/core/prebuilt_internal.mk
index 997b9be..41058ba 100644
--- a/core/prebuilt_internal.mk
+++ b/core/prebuilt_internal.mk
@@ -171,6 +171,16 @@
 # "my_strip_module not true" because otherwise the rules are defined in dynamic_binary.mk.
 endif  # my_strip_module not true
 
+# Coverage information is needed when static lib is a dependency of another
+# coverage-enabled module.
+ifeq (STATIC_LIBRARIES, $(LOCAL_MODULE_CLASS))
+GCNO_ARCHIVE := $(LOCAL_MODULE).gcnodir
+$(intermediates)/$(GCNO_ARCHIVE) : PRIVATE_ALL_OBJECTS :=
+$(intermediates)/$(GCNO_ARCHIVE) : PRIVATE_ALL_WHOLE_STATIC_LIBRARIES :=
+$(intermediates)/$(GCNO_ARCHIVE) :
+	$(transform-o-to-static-lib)
+endif
+
 ifeq ($(LOCAL_MODULE_CLASS),APPS)
 PACKAGES.$(LOCAL_MODULE).OVERRIDES := $(strip $(LOCAL_OVERRIDES_PACKAGES))
 
diff --git a/core/shared_library_internal.mk b/core/shared_library_internal.mk
index a3d95a8..05886fa 100644
--- a/core/shared_library_internal.mk
+++ b/core/shared_library_internal.mk
@@ -81,4 +81,32 @@
         $(LOCAL_ADDITIONAL_DEPENDENCIES)
 	$(transform-o-to-shared-lib)
 
+ifeq ($(my_native_coverage),true)
+gcno_suffix := .gcnodir
+
+built_whole_gcno_libraries := \
+    $(foreach lib,$(my_whole_static_libraries), \
+      $(call intermediates-dir-for, \
+        STATIC_LIBRARIES,$(lib),$(my_kind),,$(LOCAL_2ND_ARCH_VAR_PREFIX), \
+        $(my_host_cross))/$(lib)$(gcno_suffix))
+
+built_static_gcno_libraries := \
+    $(foreach lib,$(my_static_libraries), \
+      $(call intermediates-dir-for, \
+        STATIC_LIBRARIES,$(lib),$(my_kind),,$(LOCAL_2ND_ARCH_VAR_PREFIX), \
+        $(my_host_cross))/$(lib)$(gcno_suffix))
+
+GCNO_ARCHIVE := $(LOCAL_MODULE)$(gcno_suffix)
+
+$(intermediates)/$(GCNO_ARCHIVE) : PRIVATE_ALL_OBJECTS := $(strip $(LOCAL_GCNO_FILES))
+$(intermediates)/$(GCNO_ARCHIVE) : PRIVATE_ALL_WHOLE_STATIC_LIBRARIES := $(strip $(built_whole_gcno_libraries)) $(strip $(built_static_gcno_libraries))
+$(intermediates)/$(GCNO_ARCHIVE) : $(LOCAL_GCNO_FILES) $(built_whole_gcno_libraries) $(built_static_gcno_libraries)
+	$(transform-o-to-static-lib)
+
+$($(my_prefix)OUT_COVERAGE)/$(GCNO_ARCHIVE) : $(intermediates)/$(GCNO_ARCHIVE)
+	$(copy-file-to-target)
+
+$(LOCAL_BUILT_MODULE): $($(my_prefix)OUT_COVERAGE)/$(GCNO_ARCHIVE)
+endif
+
 endif  # skip_build_from_source
diff --git a/core/static_library_internal.mk b/core/static_library_internal.mk
index 2b49046..6da6a75 100644
--- a/core/static_library_internal.mk
+++ b/core/static_library_internal.mk
@@ -23,3 +23,18 @@
 $(LOCAL_BUILT_MODULE) : $(built_whole_libraries)
 $(LOCAL_BUILT_MODULE) : $(all_objects)
 	$(transform-o-to-static-lib)
+
+gcno_suffix := .gcnodir
+
+built_whole_gcno_libraries := \
+    $(foreach lib,$(my_whole_static_libraries), \
+      $(call intermediates-dir-for, \
+        STATIC_LIBRARIES,$(lib),$(my_kind),,$(LOCAL_2ND_ARCH_VAR_PREFIX), \
+        $(my_host_cross))/$(lib)$(gcno_suffix))
+
+GCNO_ARCHIVE := $(LOCAL_MODULE)$(gcno_suffix)
+
+$(intermediates)/$(GCNO_ARCHIVE) : PRIVATE_ALL_OBJECTS := $(strip $(LOCAL_GCNO_FILES))
+$(intermediates)/$(GCNO_ARCHIVE) : PRIVATE_ALL_WHOLE_STATIC_LIBRARIES := $(strip $(built_whole_gcno_libraries))
+$(intermediates)/$(GCNO_ARCHIVE) : $(LOCAL_GCNO_FILES) $(built_whole_gcno_libraries)
+	$(transform-o-to-static-lib)