diff options
Diffstat (limited to 'java')
| -rw-r--r-- | java/android_manifest.go | 4 | ||||
| -rw-r--r-- | java/androidmk.go | 10 | ||||
| -rw-r--r-- | java/base.go | 34 | ||||
| -rw-r--r-- | java/config/config.go | 22 | ||||
| -rw-r--r-- | java/config/makevars.go | 10 | ||||
| -rw-r--r-- | java/dexpreopt.go | 4 | ||||
| -rw-r--r-- | java/dexpreopt_bootjars.go | 13 | ||||
| -rw-r--r-- | java/fuzz.go | 113 | ||||
| -rw-r--r-- | java/fuzz_test.go | 43 | ||||
| -rw-r--r-- | java/lint.go | 11 | ||||
| -rw-r--r-- | java/lint_defaults.txt | 6 |
11 files changed, 202 insertions, 68 deletions
diff --git a/java/android_manifest.go b/java/android_manifest.go index 7772b7090..3fa3520ad 100644 --- a/java/android_manifest.go +++ b/java/android_manifest.go @@ -82,8 +82,8 @@ func ManifestFixer(ctx android.ModuleContext, manifest android.Path, if minSdkVersion.FinalOrFutureInt() >= 23 { args = append(args, fmt.Sprintf("--extract-native-libs=%v", !params.UseEmbeddedNativeLibs)) } else if params.UseEmbeddedNativeLibs { - ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%d doesn't support it", - minSdkVersion) + ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%s doesn't support it", + minSdkVersion.String()) } } diff --git a/java/androidmk.go b/java/androidmk.go index 80b828d45..f6ea6a930 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -132,6 +132,16 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { return entriesList } +func (j *JavaFuzzLibrary) AndroidMkEntries() []android.AndroidMkEntries { + entriesList := j.Library.AndroidMkEntries() + entries := &entriesList[0] + entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { + entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", "null-suite") + androidMkWriteTestData(j.jniFilePaths, entries) + }) + return entriesList +} + // Called for modules that are a component of a test suite. func testSuiteComponent(entries *android.AndroidMkEntries, test_suites []string, perTestcaseDirectory bool) { entries.SetString("LOCAL_MODULE_TAGS", "tests") diff --git a/java/base.go b/java/base.go index b925350a0..4932c4831 100644 --- a/java/base.go +++ b/java/base.go @@ -442,9 +442,6 @@ type Module struct { // manifest file to use instead of properties.Manifest overrideManifest android.OptionalPath - // map of SDK version to class loader context - classLoaderContexts dexpreopt.ClassLoaderContextMap - // list of plugins that this java module is exporting exportedPluginJars android.Paths @@ -1481,11 +1478,30 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { } if ctx.Device() { - lintSDKVersionString := func(sdkSpec android.SdkSpec) string { + lintSDKVersion := func(sdkSpec android.SdkSpec) int { if v := sdkSpec.ApiLevel; !v.IsPreview() { - return v.String() + return v.FinalInt() } else { - return ctx.Config().DefaultAppTargetSdk(ctx).String() + // When running metalava, we pass --version-codename. When that value + // is not REL, metalava will add 1 to the --current-version argument. + // On old branches, PLATFORM_SDK_VERSION is the latest version (for that + // branch) and the codename is REL, except potentially on the most + // recent non-master branch. On that branch, it goes through two other + // phases before it gets to the phase previously described: + // - PLATFORM_SDK_VERSION has not been updated yet, and the codename + // is not rel. This happens for most of the internal branch's life + // while the branch has been cut but is still under active development. + // - PLATFORM_SDK_VERSION has been set, but the codename is still not + // REL. This happens briefly during the release process. During this + // state the code to add --current-version is commented out, and then + // that commenting out is reverted after the codename is set to REL. + // On the master branch, the PLATFORM_SDK_VERSION always represents a + // prior version and the codename is always non-REL. + // + // We need to add one here to match metalava adding 1. Technically + // this means that in the state described in the second bullet point + // above, this number is 1 higher than it should be. + return ctx.Config().PlatformSdkVersion().FinalInt() + 1 } } @@ -1494,9 +1510,9 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { j.linter.srcJars = srcJars j.linter.classpath = append(append(android.Paths(nil), flags.bootClasspath...), flags.classpath...) j.linter.classes = j.implementationJarFile - j.linter.minSdkVersion = lintSDKVersionString(j.MinSdkVersion(ctx)) - j.linter.targetSdkVersion = lintSDKVersionString(j.TargetSdkVersion(ctx)) - j.linter.compileSdkVersion = lintSDKVersionString(j.SdkVersion(ctx)) + j.linter.minSdkVersion = lintSDKVersion(j.MinSdkVersion(ctx)) + j.linter.targetSdkVersion = lintSDKVersion(j.TargetSdkVersion(ctx)) + j.linter.compileSdkVersion = lintSDKVersion(j.SdkVersion(ctx)) j.linter.compileSdkKind = j.SdkVersion(ctx).Kind j.linter.javaLanguageLevel = flags.javaVersion.String() j.linter.kotlinLanguageLevel = "1.3" diff --git a/java/config/config.go b/java/config/config.go index 46c91a2f6..d7440022f 100644 --- a/java/config/config.go +++ b/java/config/config.go @@ -68,6 +68,11 @@ var ( "-J-XX:+TieredCompilation", "-J-XX:TieredStopAtLevel=1", } + dexerJavaVmFlagsList = []string{ + `-JXX:OnError="cat hs_err_pid%p.log"`, + "-JXX:CICompilerCount=6", + "-JXX:+UseDynamicNumberOfGCThreads", + } ) func init() { @@ -83,19 +88,14 @@ func init() { // D8 invocations are shorter lived, so we restrict their JIT tiering relative to R8. // Note that the `-JXX` prefix syntax is specific to the R8/D8 invocation wrappers. - exportedVars.ExportStringListStaticVariable("D8Flags", []string{ - `-JXX:OnError="cat hs_err_pid%p.log"`, - "-JXX:CICompilerCount=6", - "-JXX:+UseDynamicNumberOfGCThreads", + exportedVars.ExportStringListStaticVariable("D8Flags", append([]string{ + "-JXmx2048M", "-JXX:+TieredCompilation", "-JXX:TieredStopAtLevel=1", - }) - - exportedVars.ExportStringListStaticVariable("R8Flags", []string{ - `-JXX:OnError="cat hs_err_pid%p.log"`, - "-JXX:CICompilerCount=6", - "-JXX:+UseDynamicNumberOfGCThreads", - }) + }, dexerJavaVmFlagsList...)) + exportedVars.ExportStringListStaticVariable("R8Flags", append([]string{ + "-JXmx2048M", + }, dexerJavaVmFlagsList...)) exportedVars.ExportStringListStaticVariable("CommonJdkFlags", []string{ `-Xmaxerrs 9999999`, diff --git a/java/config/makevars.go b/java/config/makevars.go index bc6848fc3..273aca0b4 100644 --- a/java/config/makevars.go +++ b/java/config/makevars.go @@ -43,9 +43,10 @@ func makeVarsProvider(ctx android.MakeVarsContext) { ctx.Strict("JAVADOC", "${JavadocCmd}") ctx.Strict("COMMON_JDK_FLAGS", "${CommonJdkFlags}") - ctx.Strict("DX", "${D8Cmd}") - ctx.Strict("DX_COMMAND", "${D8Cmd} -JXms16M -JXmx2048M") - ctx.Strict("R8_COMPAT_PROGUARD", "${R8Cmd}") + ctx.Strict("D8", "${D8Cmd}") + ctx.Strict("R8", "${R8Cmd}") + ctx.Strict("D8_COMMAND", "${D8Cmd} ${D8Flags}") + ctx.Strict("R8_COMMAND", "${R8Cmd} ${R8Flags}") ctx.Strict("TURBINE", "${TurbineJar}") @@ -78,9 +79,6 @@ func makeVarsProvider(ctx android.MakeVarsContext) { ctx.Strict("CLASS2NONSDKLIST", "${Class2NonSdkList}") ctx.Strict("HIDDENAPI", "${HiddenAPI}") - ctx.Strict("D8_FLAGS", "${D8Flags}") - ctx.Strict("R8_FLAGS", "${R8Flags}") - ctx.Strict("AIDL", "${AidlCmd}") ctx.Strict("AAPT2", "${Aapt2Cmd}") ctx.Strict("ZIPALIGN", "${ZipAlign}") diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 7c5f055e6..0adaf9917 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -259,10 +259,6 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr isSystemServerJar := global.AllSystemServerJars(ctx).ContainsJar(moduleName(ctx)) bootImage := defaultBootImageConfig(ctx) - if global.UseArtImage { - bootImage = artBootImageConfig(ctx) - } - dexFiles, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp) targets := ctx.MultiTargets() diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 3d91aec91..7c4da3ef6 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -213,12 +213,6 @@ import ( // writes out a few DEXPREOPT_IMAGE_* variables for Make; these variables contain boot image names, // paths and so on. // -// 2.5. JIT-Zygote configuration -// ----------------------------- -// -// One special configuration is JIT-Zygote build, when the primary ART image is used for compiling -// apps instead of the Framework boot image extension (see DEXPREOPT_USE_ART_IMAGE and UseArtImage). -// var artApexNames = []string{ "com.android.art", @@ -938,11 +932,8 @@ func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) { ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(dexLocations, " ")) var imageNames []string - // TODO: the primary ART boot image should not be exposed to Make, as it is installed in a - // different way as a part of the ART APEX. However, there is a special JIT-Zygote build - // configuration which uses the primary ART image instead of the Framework boot image - // extension, and it relies on the ART image being exposed to Make. To fix this, it is - // necessary to rework the logic in makefiles. + // The primary ART boot image is exposed to Make for testing (gtests) and benchmarking + // (golem) purposes. for _, current := range append(d.otherImages, image) { imageNames = append(imageNames, current.name) for _, variant := range current.variants { diff --git a/java/fuzz.go b/java/fuzz.go index 257f34356..584c80b0c 100644 --- a/java/fuzz.go +++ b/java/fuzz.go @@ -15,14 +15,25 @@ package java import ( - "github.com/google/blueprint/proptools" "sort" "strings" + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" + "android/soong/android" + "android/soong/cc" "android/soong/fuzz" ) +type jniProperties struct { + // list of jni libs + Jni_libs []string + + // sanitization + Sanitizers []string +} + func init() { RegisterJavaFuzzBuildComponents(android.InitRegistrationContext) } @@ -35,11 +46,60 @@ func RegisterJavaFuzzBuildComponents(ctx android.RegistrationContext) { type JavaFuzzLibrary struct { Library fuzzPackagedModule fuzz.FuzzPackagedModule + jniProperties jniProperties + jniFilePaths android.Paths } -func (j *JavaFuzzLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { - j.Library.GenerateAndroidBuildActions(ctx) +// IsSanitizerEnabled implemented to make JavaFuzzLibrary implement +// cc.Sanitizeable +func (j *JavaFuzzLibrary) IsSanitizerEnabled(ctx android.BaseModuleContext, sanitizerName string) bool { + for _, s := range j.jniProperties.Sanitizers { + if sanitizerName == s { + return true + } + } + return false +} + +// IsSanitizerEnabledForJni implemented to make JavaFuzzLibrary implement +// cc.JniSanitizeable. It returns a bool for whether a cc dependency should be +// sanitized for the given sanitizer or not. +func (j *JavaFuzzLibrary) IsSanitizerEnabledForJni(ctx android.BaseModuleContext, sanitizerName string) bool { + return j.IsSanitizerEnabled(ctx, sanitizerName) +} + +// EnableSanitizer implemented to make JavaFuzzLibrary implement +// cc.Sanitizeable +func (j *JavaFuzzLibrary) EnableSanitizer(sanitizerName string) { +} + +// AddSanitizerDependencies implemented to make JavaFuzzLibrary implement +// cc.Sanitizeable +func (j *JavaFuzzLibrary) AddSanitizerDependencies(mctx android.BottomUpMutatorContext, sanitizerName string) { +} + +// To verify that JavaFuzzLibrary implements cc.Sanitizeable +var _ cc.Sanitizeable = (*JavaFuzzLibrary)(nil) + +func (j *JavaFuzzLibrary) DepsMutator(mctx android.BottomUpMutatorContext) { + if len(j.jniProperties.Jni_libs) > 0 { + if j.fuzzPackagedModule.FuzzProperties.Fuzz_config == nil { + config := &fuzz.FuzzConfig{} + j.fuzzPackagedModule.FuzzProperties.Fuzz_config = config + } + // this will be used by the ingestion pipeline to determine the version + // of jazzer to add to the fuzzer package + j.fuzzPackagedModule.FuzzProperties.Fuzz_config.IsJni = proptools.BoolPtr(true) + + for _, target := range mctx.MultiTargets() { + sharedLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"}) + mctx.AddFarVariationDependencies(sharedLibVariations, cc.JniFuzzLibTag, j.jniProperties.Jni_libs...) + } + } + j.Library.DepsMutator(mctx) +} +func (j *JavaFuzzLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { if j.fuzzPackagedModule.FuzzProperties.Corpus != nil { j.fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, j.fuzzPackagedModule.FuzzProperties.Corpus) } @@ -55,6 +115,23 @@ func (j *JavaFuzzLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) android.WriteFileRule(ctx, configPath, j.fuzzPackagedModule.FuzzProperties.Fuzz_config.String()) j.fuzzPackagedModule.Config = configPath } + + ctx.VisitDirectDepsWithTag(cc.JniFuzzLibTag, func(dep android.Module) { + sharedLibInfo := ctx.OtherModuleProvider(dep, cc.SharedLibraryInfoProvider).(cc.SharedLibraryInfo) + if sharedLibInfo.SharedLibrary != nil { + libPath := android.PathForModuleOut(ctx, sharedLibInfo.SharedLibrary.Base()) + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Input: sharedLibInfo.SharedLibrary, + Output: libPath, + }) + j.jniFilePaths = append(j.jniFilePaths, libPath) + } else { + ctx.PropertyErrorf("jni_libs", "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep)) + } + }) + + j.Library.GenerateAndroidBuildActions(ctx) } // java_fuzz builds and links sources into a `.jar` file for the host. @@ -65,7 +142,8 @@ func FuzzFactory() android.Module { module := &JavaFuzzLibrary{} module.addHostProperties() - module.Module.properties.Installable = proptools.BoolPtr(false) + module.AddProperties(&module.jniProperties) + module.Module.properties.Installable = proptools.BoolPtr(true) module.AddProperties(&module.fuzzPackagedModule.FuzzProperties) // java_fuzz packaging rules collide when both linux_glibc and linux_bionic are enabled, disable the linux_bionic variants. @@ -83,7 +161,7 @@ func FuzzFactory() android.Module { module.initModuleAndImport(module) android.InitSdkAwareModule(module) - InitJavaModule(module, android.HostSupported) + InitJavaModuleMultiTargets(module, android.HostSupported) return module } @@ -106,26 +184,26 @@ func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { ctx.VisitAllModules(func(module android.Module) { // Discard non-fuzz targets. - javaModule, ok := module.(*JavaFuzzLibrary) + javaFuzzModule, ok := module.(*JavaFuzzLibrary) if !ok { return } fuzzModuleValidator := fuzz.FuzzModule{ - javaModule.ModuleBase, - javaModule.DefaultableModuleBase, - javaModule.ApexModuleBase, + javaFuzzModule.ModuleBase, + javaFuzzModule.DefaultableModuleBase, + javaFuzzModule.ApexModuleBase, } - if ok := fuzz.IsValid(fuzzModuleValidator); !ok || *javaModule.Module.properties.Installable { + if ok := fuzz.IsValid(fuzzModuleValidator); !ok { return } hostOrTargetString := "target" - if javaModule.Host() { + if javaFuzzModule.Host() { hostOrTargetString = "host" } - archString := javaModule.Arch().ArchType.String() + archString := javaFuzzModule.Arch().ArchType.String() archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString) archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()} @@ -134,12 +212,17 @@ func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { builder := android.NewRuleBuilder(pctx, ctx) // Package the artifacts (data, corpus, config and dictionary into a zipfile. - files = s.PackageArtifacts(ctx, module, javaModule.fuzzPackagedModule, archDir, builder) + files = s.PackageArtifacts(ctx, module, javaFuzzModule.fuzzPackagedModule, archDir, builder) // Add .jar - files = append(files, fuzz.FileToZip{javaModule.outputFile, ""}) + files = append(files, fuzz.FileToZip{javaFuzzModule.outputFile, ""}) + + // Add jni .so files + for _, fPath := range javaFuzzModule.jniFilePaths { + files = append(files, fuzz.FileToZip{fPath, ""}) + } - archDirs[archOs], ok = s.BuildZipFile(ctx, module, javaModule.fuzzPackagedModule, files, builder, archDir, archString, "host", archOs, archDirs) + archDirs[archOs], ok = s.BuildZipFile(ctx, module, javaFuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs) if !ok { return } diff --git a/java/fuzz_test.go b/java/fuzz_test.go index cf063ebe2..0a2c94517 100644 --- a/java/fuzz_test.go +++ b/java/fuzz_test.go @@ -15,13 +15,17 @@ package java import ( - "android/soong/android" "path/filepath" + "runtime" "testing" + + "android/soong/android" + "android/soong/cc" ) var prepForJavaFuzzTest = android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, + cc.PrepareForTestWithCcBuildComponents, android.FixtureRegisterWithContext(RegisterJavaFuzzBuildComponents), ) @@ -32,6 +36,13 @@ func TestJavaFuzz(t *testing.T) { srcs: ["a.java"], libs: ["bar"], static_libs: ["baz"], + jni_libs: [ + "libjni", + ], + sanitizers: [ + "address", + "fuzzer", + ], } java_library_host { @@ -42,11 +53,21 @@ func TestJavaFuzz(t *testing.T) { java_library_host { name: "baz", srcs: ["c.java"], - }`) + } + + cc_library_shared { + name: "libjni", + host_supported: true, + device_supported: false, + stl: "none", + } + `) osCommonTarget := result.Config.BuildOSCommonTarget.String() - javac := result.ModuleForTests("foo", osCommonTarget).Rule("javac") - combineJar := result.ModuleForTests("foo", osCommonTarget).Description("for javac") + + osCommonTargetWithSan := osCommonTarget + "_asan" + "_fuzzer" + javac := result.ModuleForTests("foo", osCommonTargetWithSan).Rule("javac") + combineJar := result.ModuleForTests("foo", osCommonTargetWithSan).Description("for javac") if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" { t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs) @@ -62,4 +83,18 @@ func TestJavaFuzz(t *testing.T) { if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz { t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz) } + + ctx := result.TestContext + foo := ctx.ModuleForTests("foo", osCommonTargetWithSan).Module().(*JavaFuzzLibrary) + + expected := "libjni.so" + if runtime.GOOS == "darwin" { + expected = "libjni.dylib" + } + + fooJniFilePaths := foo.jniFilePaths + if len(fooJniFilePaths) != 1 || fooJniFilePaths[0].Rel() != expected { + t.Errorf(`expected foo test data relative path [%q], got %q`, + expected, fooJniFilePaths.Strings()) + } } diff --git a/java/lint.go b/java/lint.go index e97c9c225..f09db955d 100644 --- a/java/lint.go +++ b/java/lint.go @@ -17,6 +17,7 @@ package java import ( "fmt" "sort" + "strconv" "strings" "github.com/google/blueprint/proptools" @@ -75,9 +76,9 @@ type linter struct { extraLintCheckJars android.Paths test bool library bool - minSdkVersion string - targetSdkVersion string - compileSdkVersion string + minSdkVersion int + targetSdkVersion int + compileSdkVersion int compileSdkKind android.SdkKind javaLanguageLevel string kotlinLanguageLevel string @@ -299,7 +300,7 @@ func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleB Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`). Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`). Text(`echo " android:versionCode='1' android:versionName='1' >" &&`). - Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`, + Textf(`echo " <uses-sdk android:minSdkVersion='%d' android:targetSdkVersion='%d'/>" &&`, l.minSdkVersion, l.targetSdkVersion). Text(`echo "</manifest>"`). Text(") >").Output(manifestPath) @@ -427,7 +428,7 @@ func (l *linter) lint(ctx android.ModuleContext) { FlagWithOutput("--html ", html). FlagWithOutput("--text ", text). FlagWithOutput("--xml ", xml). - FlagWithArg("--compile-sdk-version ", l.compileSdkVersion). + FlagWithArg("--compile-sdk-version ", strconv.Itoa(l.compileSdkVersion)). FlagWithArg("--java-language-level ", l.javaLanguageLevel). FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel). FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())). diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt index 4bc0c5fd4..1eee354cd 100644 --- a/java/lint_defaults.txt +++ b/java/lint_defaults.txt @@ -28,6 +28,11 @@ --disable_check SuspiciousImport --disable_check UnusedResources --disable_check ViewConstructor +# Disable NewApi checks for the platform since platform is the one that implements +# the API. This prevents noisy lint warnings like b/228956345#1 +# NewApi checks will continue to be enforced for apex deps since +# lint.strict_updatability_linting will be true for those Soong modules +--disable_check NewApi # Downgrade existing errors to warnings --warning_check AppCompatResource # 55 occurences in 10 modules @@ -66,7 +71,6 @@ --warning_check MissingTvBanner # 3 occurences in 3 modules --warning_check NamespaceTypo # 3 occurences in 3 modules --warning_check NetworkSecurityConfig # 46 occurences in 12 modules ---warning_check NewApi # 1996 occurences in 122 modules --warning_check NotSibling # 15 occurences in 10 modules --warning_check ObjectAnimatorBinding # 14 occurences in 5 modules --warning_check OnClick # 49 occurences in 21 modules |