Skip to content

Commit

Permalink
Add JarInfer models for Android SDK 31 (Android 12) (#532)
Browse files Browse the repository at this point in the history
Generated based on AOSP tag android-12.0.0_r21.

This required minor changes to the RELEASING.md process and our
scripts, to account for changes in AOSP's build output structure.

Additionally, this PR includes a minor fix for the JarInfer
driver, which moves return-value inference code to the same
try-catch block for Wala IR generation errors as the parameter
nullability inference code, as well as a small refactoring  and
clarification of the parameter nullability inference code.
  • Loading branch information
lazaroclapp authored Dec 27, 2021
1 parent 041bca9 commit 419f98f
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 15 deletions.
2 changes: 1 addition & 1 deletion RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
2. Get a copy of the AOSP `framework_intermediates` for the corresponding Android version.
2a. At Uber? http://t.uber.com/aosp_framework_intermediate
2b. Elsewhere? You can still build the corresponding AOSP version and look for
out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/**
out/target/common/obj/JAVA_LIBRARIES/**
3. (first time) `cp jar-infer/scripts/android-jar.conf.template jar-infer/scripts/android-jar.conf`
4. Set the correct paths and versions in `android-jar.conf`
5. `rm jar-infer/android-jarinfer-models-sdk28/src/main/resources/jarinfer.astubx` (for SDK 28)
Expand Down
14 changes: 14 additions & 0 deletions jar-infer/android-jarinfer-models-sdk31/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
plugins {
id "java-library"
}

sourceCompatibility = 1.8

repositories {
mavenCentral()
}

dependencies {
}

apply plugin: 'com.vanniktech.maven.publish'
19 changes: 19 additions & 0 deletions jar-infer/android-jarinfer-models-sdk31/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#
# Copyright (C) 2021. Uber Technologies
#
# 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.
#

POM_NAME=JarInferAndroidModelsSDK31
POM_ARTIFACT_ID=android-jarinfer-models-sdk31
POM_PACKAGING=jar
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.ibm.wala.ipa.cha.ClassHierarchyException;
import com.ibm.wala.ipa.cha.ClassHierarchyFactory;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.shrikeCT.InvalidClassFileException;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.ISSABasicBlock;
import com.ibm.wala.ssa.SSAInstruction;
Expand Down Expand Up @@ -206,6 +207,14 @@ public MethodParamAnnotations run(
return nonnullParams;
}

// Check if a method includes any dereferences at all at the bytecode level
private boolean bytecodeHasAnyDereferences(IMethod mtd) throws InvalidClassFileException {
// A dereference is either a field access (o.f) or a method call (o.m())
return !CodeScanner.getFieldsRead(mtd).isEmpty()
|| !CodeScanner.getFieldsWritten(mtd).isEmpty()
|| !CodeScanner.getCallSites(mtd).isEmpty();
}

private void analyzeFile(String pkgName, String inPath, boolean includeNonPublicClasses)
throws IOException, ClassHierarchyException {
InputStream jarIS = null;
Expand Down Expand Up @@ -246,13 +255,16 @@ private void analyzeFile(String pkgName, String inPath, boolean includeNonPublic
Preconditions.checkNotNull(mtd, "method not found");
DefinitelyDerefedParams analysisDriver = null;
String sign = "";
// Parameter analysis
if (mtd.getNumberOfParameters() > (mtd.isStatic() ? 0 : 1)) {
// Skip methods by looking at bytecode
try {
if (!CodeScanner.getFieldsRead(mtd).isEmpty()
|| !CodeScanner.getFieldsWritten(mtd).isEmpty()
|| !CodeScanner.getCallSites(mtd).isEmpty()) {
try {
// Parameter analysis
if (mtd.getNumberOfParameters() > (mtd.isStatic() ? 0 : 1)) {
// For inferring parameter nullability, our criteria is based on finding
// unchecked dereferences of that parameter. We perform a quick bytecode
// check and skip methods containing no dereferences (i.e. method calls
// or field accesses) at all, avoiding the expensive IR/CFG generation
// step for these methods.
// Note that this doesn't apply to inferring return value nullability.
if (bytecodeHasAnyDereferences(mtd)) {
analysisDriver = getAnalysisDriver(mtd, options, cache);
Set<Integer> result = analysisDriver.analyze();
sign = getSignature(mtd);
Expand All @@ -265,14 +277,15 @@ private void analyzeFile(String pkgName, String inPath, boolean includeNonPublic
"Inferred Nonnull param for method: " + sign + " = " + result.toString());
}
}
} catch (Exception e) {
LOG(
DEBUG,
"DEBUG",
"Exception while scanning bytecodes for " + mtd + " " + e.getMessage());
}
// Return value analysis
analyzeReturnValue(options, cache, mtd, analysisDriver, sign);
} catch (Exception e) {
LOG(
DEBUG,
"DEBUG",
"Exception while scanning bytecodes for " + mtd + " " + e.getMessage());
}
analyzeReturnValue(options, cache, mtd, analysisDriver, sign);
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion jar-infer/scripts/android-jar.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@

### Finding android libraries ###
print "> Finding android libraries..."
cmd = "find " + ajars_dir + " -name \"*.jar\""
# Since SDK 31, the directory structure mixes classes.jar and classes-header.jar files, we use
# only the former, as classes-header.jar files are missing methods' bytecode.
cmd = "find " + ajars_dir + " -name \"*.jar\" | grep -v classes-header.jar"
ajars = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True).stdout.read().splitlines()
for ajar in ajars:
cmd = "jar tvf " + ajar + " | grep \"\.class$\" | awk '{print $8}'"
Expand Down
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ include ':compile-bench'
include ':jar-infer:android-jarinfer-models-sdk28'
include ':jar-infer:android-jarinfer-models-sdk29'
include ':jar-infer:android-jarinfer-models-sdk30'
include ':jar-infer:android-jarinfer-models-sdk31'
include ':jar-infer:jar-infer-lib'
include ':jar-infer:jar-infer-cli'
include ':jar-infer:test-java-lib-jarinfer'
Expand Down

0 comments on commit 419f98f

Please sign in to comment.