1# 2# Copyright (C) 2017 The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15# 16 17# This file sets up Java code coverage via Jacoco 18# This file is only intended to be included internally by the build system 19# (at the time of authorship, it is included by java.mk and 20# java_host_library.mk) 21 22my_include_filter := 23my_exclude_filter := 24 25ifeq ($(LOCAL_EMMA_INSTRUMENT),true) 26 ifeq ($(ANDROID_COMPILE_WITH_JACK),false) 27 # determine Jacoco include/exclude filters 28 DEFAULT_JACOCO_EXCLUDE_FILTER := org/junit/*,org/jacoco/*,org/mockito/* 29 # copy filters from Jack but also skip some known java packages 30 my_include_filter := $(strip $(LOCAL_JACK_COVERAGE_INCLUDE_FILTER)) 31 my_exclude_filter := $(strip $(DEFAULT_JACOCO_EXCLUDE_FILTER),$(LOCAL_JACK_COVERAGE_EXCLUDE_FILTER)) 32 33 # replace '.' with '/' and ',' with ' ', and quote each arg 34 ifneq ($(strip $(my_include_filter)),) 35 my_include_args := $(strip $(my_include_filter)) 36 37 my_include_args := $(subst .,/,$(my_include_args)) 38 my_include_args := '$(subst $(comma),' ',$(my_include_args))' 39 else 40 my_include_args := 41 endif 42 43 # replace '.' with '/' and ',' with ' ', and quote each arg 44 ifneq ($(strip $(my_exclude_filter)),) 45 my_exclude_args := $(my_exclude_filter) 46 47 my_exclude_args := $(subst .,/,$(my_exclude_args)) 48 my_exclude_args := $(subst $(comma)$(comma),$(comma),$(my_exclude_args)) 49 my_exclude_args := '$(subst $(comma),' ', $(my_exclude_args))' 50 else 51 my_exclude_args := 52 endif 53 endif # ANDROID_COMPILE_WITH_JACK==false 54endif # LOCAL_EMMA_INSTRUMENT == true 55 56# determine whether to run the instrumenter based on whether there is any work 57# for it to do 58ifneq ($(my_include_filter),) 59 60 my_files := $(intermediates.COMMON)/jacoco 61 62 # make a task that unzips the classes that we want to instrument from the 63 # input jar 64 my_unzipped_path := $(my_files)/work/classes-to-instrument/classes 65 my_unzipped_timestamp_path := $(my_files)/work/classes-to-instrument/updated.stamp 66$(my_unzipped_timestamp_path): PRIVATE_UNZIPPED_PATH := $(my_unzipped_path) 67$(my_unzipped_timestamp_path): PRIVATE_UNZIPPED_TIMESTAMP_PATH := $(my_unzipped_timestamp_path) 68$(my_unzipped_timestamp_path): PRIVATE_INCLUDE_ARGS := $(my_include_args) 69$(my_unzipped_timestamp_path): PRIVATE_EXCLUDE_ARGS := $(my_exclude_args) 70$(my_unzipped_timestamp_path): PRIVATE_FULL_CLASSES_PRE_JACOCO_JAR := $(LOCAL_FULL_CLASSES_PRE_JACOCO_JAR) 71$(my_unzipped_timestamp_path): $(LOCAL_FULL_CLASSES_PRE_JACOCO_JAR) 72 rm -rf $(PRIVATE_UNZIPPED_PATH) $@ 73 mkdir -p $(PRIVATE_UNZIPPED_PATH) 74 unzip -q $(PRIVATE_FULL_CLASSES_PRE_JACOCO_JAR) \ 75 -d $(PRIVATE_UNZIPPED_PATH) \ 76 $(PRIVATE_INCLUDE_ARGS) 77 rm -rf $(PRIVATE_EXCLUDE_ARGS) 78 touch $(PRIVATE_UNZIPPED_TIMESTAMP_PATH) 79# Unfortunately in the previous task above, 80# 'rm -rf $(PRIVATE_EXCLUDE_ARGS)' needs to be a separate 81# shell command after 'unzip'. 82# We can't just use the '-x' (exclude) option of 'unzip' because if both 83# inclusions and exclusions are specified and an exclusion matches no 84# inclusions, then 'unzip' exits with an error (error 11). 85# We could ignore the error, but that would make the process less reliable 86 87 88 # make a task that zips only the classes that will be instrumented 89 # (for passing in to the report generator later) 90 my_classes_to_report_on_path := $(my_files)/report-resources/jacoco-report-classes.jar 91$(my_classes_to_report_on_path): PRIVATE_UNZIPPED_PATH := $(my_unzipped_path) 92$(my_classes_to_report_on_path): $(my_unzipped_timestamp_path) 93 rm -f $@ 94 zip -q $@ \ 95 -r $(PRIVATE_UNZIPPED_PATH) 96 97 98 99 # make a task that invokes instrumentation 100 my_instrumented_path := $(my_files)/work/instrumented/classes 101 my_instrumented_timestamp_path := $(my_files)/work/instrumented/updated.stamp 102$(my_instrumented_timestamp_path): PRIVATE_INSTRUMENTED_PATH := $(my_instrumented_path) 103$(my_instrumented_timestamp_path): PRIVATE_INSTRUMENTED_TIMESTAMP_PATH := $(my_instrumented_timestamp_path) 104$(my_instrumented_timestamp_path): PRIVATE_UNZIPPED_PATH := $(my_unzipped_path) 105$(my_instrumented_timestamp_path): $(my_unzipped_timestamp_path) $(JACOCO_CLI_JAR) 106 rm -rf $(PRIVATE_INSTRUMENTED_PATH) 107 mkdir -p $(PRIVATE_INSTRUMENTED_PATH) 108 java -jar $(JACOCO_CLI_JAR) \ 109 instrument \ 110 -quiet \ 111 -dest '$(PRIVATE_INSTRUMENTED_PATH)' \ 112 $(PRIVATE_UNZIPPED_PATH) 113 touch $(PRIVATE_INSTRUMENTED_TIMESTAMP_PATH) 114 115 116 # make a task that zips both the instrumented classes and the uninstrumented 117 # classes (this jar is the instrumented application to execute) 118 my_temp_jar_path := $(my_files)/work/usable.jar 119 LOCAL_FULL_CLASSES_JACOCO_JAR := $(intermediates.COMMON)/classes-jacoco.jar 120$(LOCAL_FULL_CLASSES_JACOCO_JAR): PRIVATE_TEMP_JAR_PATH := $(my_temp_jar_path) 121$(LOCAL_FULL_CLASSES_JACOCO_JAR): PRIVATE_INSTRUMENTED_PATH := $(my_instrumented_path) 122$(LOCAL_FULL_CLASSES_JACOCO_JAR): PRIVATE_FULL_CLASSES_PRE_JACOCO_JAR := $(LOCAL_FULL_CLASSES_PRE_JACOCO_JAR) 123$(LOCAL_FULL_CLASSES_JACOCO_JAR): $(my_instrumented_timestamp_path) $(LOCAL_FULL_CLASSES_PRE_JACOCO_JAR) 124 rm -f $@ $(PRIVATE_TEMP_JAR_PATH) 125 # copy the pre-jacoco jar (containing files excluded from instrumentation) 126 cp $(PRIVATE_FULL_CLASSES_PRE_JACOCO_JAR) $(PRIVATE_TEMP_JAR_PATH) 127 # copy instrumented files back into the resultant jar 128 $(JAR) -uf $(PRIVATE_TEMP_JAR_PATH) -C $(PRIVATE_INSTRUMENTED_PATH) . 129 mv $(PRIVATE_TEMP_JAR_PATH) $@ 130 131 # this is used to trigger $(my_classes_to_report_on_path) to build 132 # when $(LOCAL_FULL_CLASSES_JACOCO_JAR) builds, but it isn't truly a 133 # dependency. 134$(LOCAL_FULL_CLASSES_JACOCO_JAR): $(my_classes_to_report_on_path) 135 136else # my_include_filter == '' 137 LOCAL_FULL_CLASSES_JACOCO_JAR := $(LOCAL_FULL_CLASSES_PRE_JACOCO_JAR) 138endif # my_include_filter != '' 139 140LOCAL_INTERMEDIATE_TARGETS += $(LOCAL_FULL_CLASSES_JACOCO_JAR) 141