Merge "Added new framework-pdf jar inside MediaProvider module" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 8670b4d..f0b7598 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -13,6 +13,8 @@
// limitations under the License.
aconfig_srcjars = [
+ ":android.hardware.biometrics.flags-aconfig-java{.generated_srcjars}",
+ ":android.nfc.flags-aconfig-java{.generated_srcjars}",
":android.os.flags-aconfig-java{.generated_srcjars}",
":android.security.flags-aconfig-java{.generated_srcjars}",
":com.android.hardware.camera2-aconfig-java{.generated_srcjars}",
@@ -109,6 +111,19 @@
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+// NFC
+aconfig_declarations {
+ name: "android.nfc.flags-aconfig",
+ package: "android.nfc",
+ srcs: ["core/java/android/nfc/*.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.nfc.flags-aconfig-java",
+ aconfig_declarations: "android.nfc.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
// Security
aconfig_declarations {
name: "android.security.flags-aconfig",
@@ -129,3 +144,16 @@
test: true,
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+
+// Biometrics
+aconfig_declarations {
+ name: "android.hardware.biometrics.flags-aconfig",
+ package: "android.hardware.biometrics",
+ srcs: ["core/java/android/hardware/biometrics/flags.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.hardware.biometrics.flags-aconfig-java",
+ aconfig_declarations: "android.hardware.biometrics.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index c05d300..8b53592 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -66,6 +66,7 @@
tag: ".removed-api.txt",
},
],
+ api_surface: "public",
}
priv_apps = " --show-annotation android.annotation.SystemApi\\(" +
@@ -84,6 +85,9 @@
droidstubs {
name: "system-api-stubs-docs-non-updatable",
+ srcs: [
+ ":framework-minus-apex-aconfig-srcjars",
+ ],
defaults: [
"android-non-updatable-stubs-defaults",
"module-classpath-stubs-defaults",
@@ -119,10 +123,14 @@
tag: ".removed-api.txt",
},
],
+ api_surface: "system",
}
droidstubs {
name: "test-api-stubs-docs-non-updatable",
+ srcs: [
+ ":framework-minus-apex-aconfig-srcjars",
+ ],
defaults: [
"android-non-updatable-stubs-defaults",
"module-classpath-stubs-defaults",
@@ -164,10 +172,14 @@
tag: ".removed-api.txt",
},
],
+ api_surface: "test",
}
droidstubs {
name: "module-lib-api-stubs-docs-non-updatable",
+ srcs: [
+ ":framework-minus-apex-aconfig-srcjars",
+ ],
defaults: [
"android-non-updatable-stubs-defaults",
"module-classpath-stubs-defaults",
@@ -203,6 +215,7 @@
tag: ".removed-api.txt",
},
],
+ api_surface: "module-lib",
}
/////////////////////////////////////////////////////////////////////
@@ -379,8 +392,8 @@
java_api_library {
name: "android-non-updatable.stubs.from-text",
api_surface: "public",
- api_files: [
- ":non-updatable-current.txt",
+ api_contributions: [
+ "api-stubs-docs-non-updatable.api.contribution",
],
defaults: ["android-non-updatable_from_text_defaults"],
full_api_surface_stub: "android_stubs_current.from-text",
@@ -389,9 +402,9 @@
java_api_library {
name: "android-non-updatable.stubs.system.from-text",
api_surface: "system",
- api_files: [
- ":non-updatable-current.txt",
- ":non-updatable-system-current.txt",
+ api_contributions: [
+ "api-stubs-docs-non-updatable.api.contribution",
+ "system-api-stubs-docs-non-updatable.api.contribution",
],
defaults: ["android-non-updatable_from_text_defaults"],
full_api_surface_stub: "android_system_stubs_current.from-text",
@@ -400,10 +413,10 @@
java_api_library {
name: "android-non-updatable.stubs.test.from-text",
api_surface: "test",
- api_files: [
- ":non-updatable-current.txt",
- ":non-updatable-system-current.txt",
- ":non-updatable-test-current.txt",
+ api_contributions: [
+ "api-stubs-docs-non-updatable.api.contribution",
+ "system-api-stubs-docs-non-updatable.api.contribution",
+ "test-api-stubs-docs-non-updatable.api.contribution",
],
defaults: ["android-non-updatable_from_text_defaults"],
full_api_surface_stub: "android_test_stubs_current.from-text",
@@ -412,10 +425,10 @@
java_api_library {
name: "android-non-updatable.stubs.module_lib.from-text",
api_surface: "module_lib",
- api_files: [
- ":non-updatable-current.txt",
- ":non-updatable-system-current.txt",
- ":non-updatable-module-lib-current.txt",
+ api_contributions: [
+ "api-stubs-docs-non-updatable.api.contribution",
+ "system-api-stubs-docs-non-updatable.api.contribution",
+ "module-lib-api-stubs-docs-non-updatable.api.contribution",
],
defaults: ["android-non-updatable_from_text_defaults"],
full_api_surface_stub: "android_module_lib_stubs_current_full.from-text",
@@ -598,7 +611,6 @@
name: "android_test_stubs_current_contributions",
api_surface: "test",
api_contributions: [
- "test-api-stubs-docs-non-updatable.api.contribution",
"framework-virtualization.stubs.source.test.api.contribution",
],
}
@@ -664,6 +676,7 @@
api_contributions: [
"api-stubs-docs-non-updatable.api.contribution",
"system-api-stubs-docs-non-updatable.api.contribution",
+ "test-api-stubs-docs-non-updatable.api.contribution",
],
visibility: ["//visibility:public"],
}
diff --git a/boot/Android.bp b/boot/Android.bp
index 851294c..6b90f10 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -192,6 +192,13 @@
],
}
+genrule { // This module exists to make the srcjar output available to Make.
+ name: "platform-bootclasspath.srcjar",
+ srcs: [":platform-bootclasspath{.srcjar}"],
+ out: ["platform-bootclasspath.srcjar"],
+ cmd: "cp $(in) $(out)",
+}
+
platform_systemserverclasspath {
name: "platform-systemserverclasspath",
}
diff --git a/core/api/current.txt b/core/api/current.txt
index cba935f..d399e34 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -37935,6 +37935,7 @@
method @Nullable public java.util.Date getKeyValidityStart();
method @NonNull public String getKeystoreAlias();
method public int getMaxUsageCount();
+ method @FlaggedApi("MGF1_DIGEST_SETTER") @NonNull public java.util.Set<java.lang.String> getMgf1Digests();
method public int getPurposes();
method @NonNull public String[] getSignaturePaddings();
method public int getUserAuthenticationType();
@@ -37942,6 +37943,7 @@
method public boolean isDevicePropertiesAttestationIncluded();
method @NonNull public boolean isDigestsSpecified();
method public boolean isInvalidatedByBiometricEnrollment();
+ method @FlaggedApi("MGF1_DIGEST_SETTER") @NonNull public boolean isMgf1DigestsSpecified();
method public boolean isRandomizedEncryptionRequired();
method public boolean isStrongBoxBacked();
method public boolean isUnlockedDeviceRequired();
@@ -37973,6 +37975,7 @@
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityStart(java.util.Date);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMaxUsageCount(int);
+ method @FlaggedApi("MGF1_DIGEST_SETTER") @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMgf1Digests(@Nullable java.lang.String...);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
@@ -38077,12 +38080,14 @@
method @Nullable public java.util.Date getKeyValidityForOriginationEnd();
method @Nullable public java.util.Date getKeyValidityStart();
method public int getMaxUsageCount();
+ method @FlaggedApi("MGF1_DIGEST_SETTER") @NonNull public java.util.Set<java.lang.String> getMgf1Digests();
method public int getPurposes();
method @NonNull public String[] getSignaturePaddings();
method public int getUserAuthenticationType();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isDigestsSpecified();
method public boolean isInvalidatedByBiometricEnrollment();
+ method @FlaggedApi("MGF1_DIGEST_SETTER") @NonNull public boolean isMgf1DigestsSpecified();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUnlockedDeviceRequired();
method public boolean isUserAuthenticationRequired();
@@ -38104,6 +38109,7 @@
method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
method @NonNull public android.security.keystore.KeyProtection.Builder setMaxUsageCount(int);
+ method @FlaggedApi("MGF1_DIGEST_SETTER") @NonNull public android.security.keystore.KeyProtection.Builder setMgf1Digests(@Nullable java.lang.String...);
method @NonNull public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
method @NonNull public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
method @NonNull public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index c1c2788..eda6057 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -9140,6 +9140,73 @@
}
+package android.nfc.cardemulation {
+
+ @FlaggedApi("android.nfc.enable_nfc_mainline") public final class AidGroup implements android.os.Parcelable {
+ ctor @FlaggedApi("android.nfc.enable_nfc_mainline") public AidGroup(@NonNull java.util.List<java.lang.String>, @Nullable String);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @Nullable public static android.nfc.cardemulation.AidGroup createFromXml(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public int describeContents();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dump(@NonNull android.util.proto.ProtoOutputStream);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<java.lang.String> getAids();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public String getCategory();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public void writeAsXml(@NonNull org.xmlpull.v1.XmlSerializer) throws java.io.IOException;
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.AidGroup> CREATOR;
+ }
+
+ @FlaggedApi("android.nfc.enable_nfc_mainline") public final class ApduServiceInfo implements android.os.Parcelable {
+ ctor @FlaggedApi("android.nfc.enable_nfc_mainline") public ApduServiceInfo(@NonNull android.content.pm.PackageManager, @NonNull android.content.pm.ResolveInfo, boolean) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public int describeContents();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dump(@NonNull android.os.ParcelFileDescriptor, @NonNull java.io.PrintWriter, @NonNull String[]);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dumpDebug(@NonNull android.util.proto.ProtoOutputStream);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<android.nfc.cardemulation.AidGroup> getAidGroups();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<java.lang.String> getAids();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public String getCategoryForAid(@NonNull String);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public android.content.ComponentName getComponent();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public String getDescription();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public android.nfc.cardemulation.AidGroup getDynamicAidGroupForCategory(@NonNull String);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @Nullable public String getOffHostSecureElement();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<java.lang.String> getPrefixAids();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public String getSettingsActivityName();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<java.lang.String> getSubsetAids();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public int getUid();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean hasCategory(@NonNull String);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean isOnHost();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public CharSequence loadAppLabel(@NonNull android.content.pm.PackageManager);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public android.graphics.drawable.Drawable loadBanner(@NonNull android.content.pm.PackageManager);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public android.graphics.drawable.Drawable loadIcon(@NonNull android.content.pm.PackageManager);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public CharSequence loadLabel(@NonNull android.content.pm.PackageManager);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public boolean removeDynamicAidGroupForCategory(@NonNull String);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean requiresScreenOn();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean requiresUnlock();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public void resetOffHostSecureElement();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setDynamicAidGroup(@NonNull android.nfc.cardemulation.AidGroup);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setOffHostSecureElement(@NonNull String);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.ApduServiceInfo> CREATOR;
+ }
+
+ @FlaggedApi("android.nfc.enable_nfc_mainline") public final class NfcFServiceInfo implements android.os.Parcelable {
+ ctor @FlaggedApi("android.nfc.enable_nfc_mainline") public NfcFServiceInfo(@NonNull android.content.pm.PackageManager, @NonNull android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public int describeContents();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dump(@NonNull android.os.ParcelFileDescriptor, @NonNull java.io.PrintWriter, @NonNull String[]);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dumpDebug(@NonNull android.util.proto.ProtoOutputStream);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public android.content.ComponentName getComponent();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public String getDescription();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public String getNfcid2();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public String getSystemCode();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public String getT3tPmm();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public int getUid();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public android.graphics.drawable.Drawable loadIcon(@NonNull android.content.pm.PackageManager);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public CharSequence loadLabel(@NonNull android.content.pm.PackageManager);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setDynamicNfcid2(@NonNull String);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setDynamicSystemCode(@NonNull String);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.NfcFServiceInfo> CREATOR;
+ }
+
+}
+
package android.os {
public class BatteryManager {
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index 0100f0e..71c02dc 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -225,3 +225,16 @@
SAM-compatible parameters (such as parameter 1, "listener", in android.view.accessibility.AccessibilityManager.addTouchExplorationStateChangeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.webkit.WebChromeClient#onShowFileChooser(android.webkit.WebView, android.webkit.ValueCallback<android.net.Uri[]>, android.webkit.WebChromeClient.FileChooserParams):
SAM-compatible parameters (such as parameter 2, "filePathCallback", in android.webkit.WebChromeClient.onShowFileChooser) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+
+UnflaggedApi: android.nfc.cardemulation.AidGroup#CONTENTS_FILE_DESCRIPTOR:
+ New API must be flagged with @FlaggedApi: field android.nfc.cardemulation.AidGroup.CONTENTS_FILE_DESCRIPTOR
+UnflaggedApi: android.nfc.cardemulation.AidGroup#PARCELABLE_WRITE_RETURN_VALUE:
+ New API must be flagged with @FlaggedApi: field android.nfc.cardemulation.AidGroup.PARCELABLE_WRITE_RETURN_VALUE
+UnflaggedApi: android.nfc.cardemulation.ApduServiceInfo#CONTENTS_FILE_DESCRIPTOR:
+ New API must be flagged with @FlaggedApi: field android.nfc.cardemulation.ApduServiceInfo.CONTENTS_FILE_DESCRIPTOR
+UnflaggedApi: android.nfc.cardemulation.ApduServiceInfo#PARCELABLE_WRITE_RETURN_VALUE:
+ New API must be flagged with @FlaggedApi: field android.nfc.cardemulation.ApduServiceInfo.PARCELABLE_WRITE_RETURN_VALUE
+UnflaggedApi: android.nfc.cardemulation.NfcFServiceInfo#CONTENTS_FILE_DESCRIPTOR:
+ New API must be flagged with @FlaggedApi: field android.nfc.cardemulation.NfcFServiceInfo.CONTENTS_FILE_DESCRIPTOR
+UnflaggedApi: android.nfc.cardemulation.NfcFServiceInfo#PARCELABLE_WRITE_RETURN_VALUE:
+ New API must be flagged with @FlaggedApi: field android.nfc.cardemulation.NfcFServiceInfo.PARCELABLE_WRITE_RETURN_VALUE
diff --git a/core/java/android/hardware/biometrics/flags.aconfig b/core/java/android/hardware/biometrics/flags.aconfig
new file mode 100644
index 0000000..0924e0d1
--- /dev/null
+++ b/core/java/android/hardware/biometrics/flags.aconfig
@@ -0,0 +1,8 @@
+package: "android.hardware.biometrics"
+
+flag {
+ name: "add_key_agreement_crypto_object"
+ namespace: "biometrics"
+ description: "Feature flag for adding KeyAgreement api to CryptoObject."
+ bug: "282058146"
+}
diff --git a/core/java/android/net/metrics/WakeupEvent.java b/core/java/android/net/metrics/WakeupEvent.java
index af9a73c..53a3ea5 100644
--- a/core/java/android/net/metrics/WakeupEvent.java
+++ b/core/java/android/net/metrics/WakeupEvent.java
@@ -29,7 +29,7 @@
public String iface;
public int uid;
public int ethertype;
- public MacAddress dstHwAddr;
+ public MacAddress dstHwAddr; // actually used to store a src mac address
public String srcIp;
public String dstIp;
public int ipNextHeader;
@@ -44,7 +44,7 @@
j.add(iface);
j.add("uid: " + Integer.toString(uid));
j.add("eth=0x" + Integer.toHexString(ethertype));
- j.add("dstHw=" + dstHwAddr);
+ j.add("srcMac=" + dstHwAddr); // really!! http://b/292404319#comment11
if (ipNextHeader > 0) {
j.add("ipNxtHdr=" + ipNextHeader);
j.add("srcIp=" + srcIp);
diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java
index 2436e57..958669e 100644
--- a/core/java/android/nfc/cardemulation/AidGroup.java
+++ b/core/java/android/nfc/cardemulation/AidGroup.java
@@ -16,7 +16,11 @@
package android.nfc.cardemulation;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.nfc.Flags;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -29,6 +33,11 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
+
+/**********************************************************************
+ * This file is not a part of the NFC mainline module *
+ * *******************************************************************/
/**
* The AidGroup class represents a group of Application Identifiers (AIDs).
@@ -39,28 +48,30 @@
*
* @hide
*/
+@SystemApi
+@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
public final class AidGroup implements Parcelable {
/**
* The maximum number of AIDs that can be present in any one group.
*/
- public static final int MAX_NUM_AIDS = 256;
+ private static final int MAX_NUM_AIDS = 256;
- static final String TAG = "AidGroup";
+ private static final String TAG = "AidGroup";
- @UnsupportedAppUsage
- final List<String> aids;
- @UnsupportedAppUsage
- final String category;
- @UnsupportedAppUsage
- final String description;
+
+ private final List<String> mAids;
+ private final String mCategory;
+ @SuppressWarnings("unused") // Unused as of now, but part of the XML input.
+ private final String mDescription;
/**
* Creates a new AidGroup object.
*
- * @param aids The list of AIDs present in the group
- * @param category The category of this group, e.g. {@link CardEmulation#CATEGORY_PAYMENT}
+ * @param aids list of AIDs present in the group
+ * @param category category of this group, e.g. {@link CardEmulation#CATEGORY_PAYMENT}
*/
- public AidGroup(List<String> aids, String category) {
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ public AidGroup(@NonNull List<String> aids, @Nullable String category) {
if (aids == null || aids.size() == 0) {
throw new IllegalArgumentException("No AIDS in AID group.");
}
@@ -73,45 +84,55 @@
}
}
if (isValidCategory(category)) {
- this.category = category;
+ this.mCategory = category;
} else {
- this.category = CardEmulation.CATEGORY_OTHER;
+ this.mCategory = CardEmulation.CATEGORY_OTHER;
}
- this.aids = new ArrayList<String>(aids.size());
+ this.mAids = new ArrayList<String>(aids.size());
for (String aid : aids) {
- this.aids.add(aid.toUpperCase());
+ this.mAids.add(aid.toUpperCase(Locale.US));
}
- this.description = null;
- }
-
- @UnsupportedAppUsage
- AidGroup(String category, String description) {
- this.aids = new ArrayList<String>();
- this.category = category;
- this.description = description;
+ this.mDescription = null;
}
/**
+ * Creates a new AidGroup object.
+ *
+ * @param category category of this group, e.g. {@link CardEmulation#CATEGORY_PAYMENT}
+ * @param description description of this group
+ */
+ AidGroup(@NonNull String category, @NonNull String description) {
+ this.mAids = new ArrayList<String>();
+ this.mCategory = category;
+ this.mDescription = description;
+ }
+
+ /**
+ * Returns the category of this group.
* @return the category of this AID group
*/
- @UnsupportedAppUsage
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
public String getCategory() {
- return category;
+ return mCategory;
}
/**
+ * Returns the list of AIDs in this group.
+ *
* @return the list of AIDs in this group
*/
- @UnsupportedAppUsage
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
public List<String> getAids() {
- return aids;
+ return mAids;
}
@Override
public String toString() {
- StringBuilder out = new StringBuilder("Category: " + category +
- ", AIDs:");
- for (String aid : aids) {
+ StringBuilder out = new StringBuilder("Category: " + mCategory
+ + ", AIDs:");
+ for (String aid : mAids) {
out.append(aid);
out.append(", ");
}
@@ -119,41 +140,44 @@
}
/**
- * Dump debugging info as AidGroupProto
+ * Dump debugging info as AidGroupProto.
*
* If the output belongs to a sub message, the caller is responsible for wrapping this function
* between {@link ProtoOutputStream#start(long)} and {@link ProtoOutputStream#end(long)}.
*
* @param proto the ProtoOutputStream to write to
*/
- public void dump(ProtoOutputStream proto) {
- proto.write(AidGroupProto.CATEGORY, category);
- for (String aid : aids) {
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ public void dump(@NonNull ProtoOutputStream proto) {
+ proto.write(AidGroupProto.CATEGORY, mCategory);
+ for (String aid : mAids) {
proto.write(AidGroupProto.AIDS, aid);
}
}
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
@Override
public int describeContents() {
return 0;
}
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
@Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(category);
- dest.writeInt(aids.size());
- if (aids.size() > 0) {
- dest.writeStringList(aids);
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString8(mCategory);
+ dest.writeInt(mAids.size());
+ if (mAids.size() > 0) {
+ dest.writeStringList(mAids);
}
}
- @UnsupportedAppUsage
- public static final @android.annotation.NonNull Parcelable.Creator<AidGroup> CREATOR =
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ public static final @NonNull Parcelable.Creator<AidGroup> CREATOR =
new Parcelable.Creator<AidGroup>() {
@Override
public AidGroup createFromParcel(Parcel source) {
- String category = source.readString();
+ String category = source.readString8();
int listSize = source.readInt();
ArrayList<String> aidList = new ArrayList<String>();
if (listSize > 0) {
@@ -168,8 +192,17 @@
}
};
- @UnsupportedAppUsage
- static public AidGroup createFromXml(XmlPullParser parser) throws XmlPullParserException, IOException {
+ /**
+ * Create an instance of AID group from XML file.
+ *
+ * @param parser input xml parser stream
+ * @throws XmlPullParserException If an error occurs parsing the element.
+ * @throws IOException If an error occurs reading the element.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @Nullable
+ public static AidGroup createFromXml(@NonNull XmlPullParser parser)
+ throws XmlPullParserException, IOException {
String category = null;
ArrayList<String> aids = new ArrayList<String>();
AidGroup group = null;
@@ -210,11 +243,16 @@
return group;
}
- @UnsupportedAppUsage
- public void writeAsXml(XmlSerializer out) throws IOException {
+ /**
+ * Serialize instance of AID group to XML file.
+ * @param out XML serializer stream
+ * @throws IOException If an error occurs reading the element.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ public void writeAsXml(@NonNull XmlSerializer out) throws IOException {
out.startTag(null, "aid-group");
- out.attribute(null, "category", category);
- for (String aid : aids) {
+ out.attribute(null, "category", mCategory);
+ for (String aid : mAids) {
out.startTag(null, "aid");
out.attribute(null, "value", aid);
out.endTag(null, "aid");
@@ -222,7 +260,7 @@
out.endTag(null, "aid-group");
}
- static boolean isValidCategory(String category) {
+ private static boolean isValidCategory(String category) {
return CardEmulation.CATEGORY_PAYMENT.equals(category) ||
CardEmulation.CATEGORY_OTHER.equals(category);
}
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 793a70e..18ec914 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -14,10 +14,16 @@
* limitations under the License.
*/
+/**********************************************************************
+ * This file is not a part of the NFC mainline module *
+ * *******************************************************************/
+
package android.nfc.cardemulation;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.SystemApi;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -28,7 +34,9 @@
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
+import android.nfc.Flags;
import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
@@ -38,7 +46,6 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -47,82 +54,82 @@
import java.util.Map;
/**
+ * Class holding APDU service info.
+ *
* @hide
*/
+@SystemApi
+@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
public final class ApduServiceInfo implements Parcelable {
- static final String TAG = "ApduServiceInfo";
+ private static final String TAG = "ApduServiceInfo";
/**
* The service that implements this
*/
- @UnsupportedAppUsage
- final ResolveInfo mService;
+ private final ResolveInfo mService;
/**
* Description of the service
*/
- final String mDescription;
+ private final String mDescription;
/**
* Whether this service represents AIDs running on the host CPU
*/
- final boolean mOnHost;
+ private final boolean mOnHost;
/**
* Offhost reader name.
* eg: SIM, eSE etc
*/
- String mOffHostName;
+ private String mOffHostName;
/**
* Offhost reader name from manifest file.
- * Used for unsetOffHostSecureElement()
+ * Used for resetOffHostSecureElement()
*/
- final String mStaticOffHostName;
+ private final String mStaticOffHostName;
/**
* Mapping from category to static AID group
*/
- @UnsupportedAppUsage
- final HashMap<String, AidGroup> mStaticAidGroups;
+ private final HashMap<String, AidGroup> mStaticAidGroups;
/**
* Mapping from category to dynamic AID group
*/
- @UnsupportedAppUsage
- final HashMap<String, AidGroup> mDynamicAidGroups;
+ private final HashMap<String, AidGroup> mDynamicAidGroups;
/**
* Whether this service should only be started when the device is unlocked.
*/
- final boolean mRequiresDeviceUnlock;
+ private final boolean mRequiresDeviceUnlock;
/**
* Whether this service should only be started when the device is screen on.
*/
- final boolean mRequiresDeviceScreenOn;
+ private final boolean mRequiresDeviceScreenOn;
/**
* The id of the service banner specified in XML.
*/
- final int mBannerResourceId;
+ private final int mBannerResourceId;
/**
* The uid of the package the service belongs to
*/
- final int mUid;
+ private final int mUid;
/**
* Settings Activity for this service
*/
- final String mSettingsActivityName;
+ private final String mSettingsActivityName;
/**
* @hide
*/
- @UnsupportedAppUsage
public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
- ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
+ List<AidGroup> staticAidGroups, List<AidGroup> dynamicAidGroups,
boolean requiresUnlock, int bannerResource, int uid,
String settingsActivityName, String offHost, String staticOffHost) {
this(info, onHost, description, staticAidGroups, dynamicAidGroups,
@@ -134,7 +141,7 @@
* @hide
*/
public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
- ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
+ List<AidGroup> staticAidGroups, List<AidGroup> dynamicAidGroups,
boolean requiresUnlock, boolean requiresScreenOn, int bannerResource, int uid,
String settingsActivityName, String offHost, String staticOffHost) {
this.mService = info;
@@ -147,19 +154,28 @@
this.mRequiresDeviceUnlock = requiresUnlock;
this.mRequiresDeviceScreenOn = requiresScreenOn;
for (AidGroup aidGroup : staticAidGroups) {
- this.mStaticAidGroups.put(aidGroup.category, aidGroup);
+ this.mStaticAidGroups.put(aidGroup.getCategory(), aidGroup);
}
for (AidGroup aidGroup : dynamicAidGroups) {
- this.mDynamicAidGroups.put(aidGroup.category, aidGroup);
+ this.mDynamicAidGroups.put(aidGroup.getCategory(), aidGroup);
}
this.mBannerResourceId = bannerResource;
this.mUid = uid;
this.mSettingsActivityName = settingsActivityName;
}
- @UnsupportedAppUsage
- public ApduServiceInfo(PackageManager pm, ResolveInfo info, boolean onHost) throws
- XmlPullParserException, IOException {
+ /**
+ * Creates a new ApduServiceInfo object.
+ *
+ * @param pm packageManager instance
+ * @param info app component info
+ * @param onHost whether service is on host or not (secure element)
+ * @throws XmlPullParserException If an error occurs parsing the element.
+ * @throws IOException If an error occurs reading the element.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ public ApduServiceInfo(@NonNull PackageManager pm, @NonNull ResolveInfo info, boolean onHost)
+ throws XmlPullParserException, IOException {
ServiceInfo si = info.serviceInfo;
XmlResourceParser parser = null;
try {
@@ -277,9 +293,9 @@
groupAttrs.recycle();
} else if (eventType == XmlPullParser.END_TAG && "aid-group".equals(tagName) &&
currentGroup != null) {
- if (currentGroup.aids.size() > 0) {
- if (!mStaticAidGroups.containsKey(currentGroup.category)) {
- mStaticAidGroups.put(currentGroup.category, currentGroup);
+ if (currentGroup.getAids().size() > 0) {
+ if (!mStaticAidGroups.containsKey(currentGroup.getCategory())) {
+ mStaticAidGroups.put(currentGroup.getCategory(), currentGroup);
}
} else {
Log.e(TAG, "Not adding <aid-group> with empty or invalid AIDs");
@@ -291,8 +307,8 @@
com.android.internal.R.styleable.AidFilter);
String aid = a.getString(com.android.internal.R.styleable.AidFilter_name).
toUpperCase();
- if (CardEmulation.isValidAid(aid) && !currentGroup.aids.contains(aid)) {
- currentGroup.aids.add(aid);
+ if (CardEmulation.isValidAid(aid) && !currentGroup.getAids().contains(aid)) {
+ currentGroup.getAids().add(aid);
} else {
Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid);
}
@@ -305,8 +321,8 @@
toUpperCase();
// Add wildcard char to indicate prefix
aid = aid.concat("*");
- if (CardEmulation.isValidAid(aid) && !currentGroup.aids.contains(aid)) {
- currentGroup.aids.add(aid);
+ if (CardEmulation.isValidAid(aid) && !currentGroup.getAids().contains(aid)) {
+ currentGroup.getAids().add(aid);
} else {
Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid);
}
@@ -319,8 +335,8 @@
toUpperCase();
// Add wildcard char to indicate suffix
aid = aid.concat("#");
- if (CardEmulation.isValidAid(aid) && !currentGroup.aids.contains(aid)) {
- currentGroup.aids.add(aid);
+ if (CardEmulation.isValidAid(aid) && !currentGroup.getAids().contains(aid)) {
+ currentGroup.getAids().add(aid);
} else {
Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid);
}
@@ -336,11 +352,25 @@
mUid = si.applicationInfo.uid;
}
+ /**
+ * Returns the app component corresponding to this APDU service.
+ *
+ * @return app component for this service
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
public ComponentName getComponent() {
return new ComponentName(mService.serviceInfo.packageName,
mService.serviceInfo.name);
}
+ /**
+ * Returns the offhost secure element name (if the service is offhost).
+ *
+ * @return offhost secure element name for offhost services
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @Nullable
public String getOffHostSecureElement() {
return mOffHostName;
}
@@ -353,18 +383,30 @@
* for that category.
* @return List of AIDs registered by the service
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
public List<String> getAids() {
final ArrayList<String> aids = new ArrayList<String>();
for (AidGroup group : getAidGroups()) {
- aids.addAll(group.aids);
+ aids.addAll(group.getAids());
}
return aids;
}
+ /**
+ * Returns a consolidated list of AIDs with prefixes from the AID groups
+ * registered by this service. Note that if a service has both
+ * a static (manifest-based) AID group for a category and a dynamic
+ * AID group, only the dynamically registered AIDs will be returned
+ * for that category.
+ * @return List of prefix AIDs registered by the service
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
public List<String> getPrefixAids() {
final ArrayList<String> prefixAids = new ArrayList<String>();
for (AidGroup group : getAidGroups()) {
- for (String aid : group.aids) {
+ for (String aid : group.getAids()) {
if (aid.endsWith("*")) {
prefixAids.add(aid);
}
@@ -373,10 +415,20 @@
return prefixAids;
}
+ /**
+ * Returns a consolidated list of AIDs with subsets from the AID groups
+ * registered by this service. Note that if a service has both
+ * a static (manifest-based) AID group for a category and a dynamic
+ * AID group, only the dynamically registered AIDs will be returned
+ * for that category.
+ * @return List of prefix AIDs registered by the service
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
public List<String> getSubsetAids() {
final ArrayList<String> subsetAids = new ArrayList<String>();
for (AidGroup group : getAidGroups()) {
- for (String aid : group.aids) {
+ for (String aid : group.getAids()) {
if (aid.endsWith("#")) {
subsetAids.add(aid);
}
@@ -384,14 +436,28 @@
}
return subsetAids;
}
+
/**
* Returns the registered AID group for this category.
+ *
+ * @param category category name
+ * @return {@link AidGroup} instance for the provided category
*/
- public AidGroup getDynamicAidGroupForCategory(String category) {
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
+ public AidGroup getDynamicAidGroupForCategory(@NonNull String category) {
return mDynamicAidGroups.get(category);
}
- public boolean removeDynamicAidGroupForCategory(String category) {
+ /**
+ * Removes the registered AID group for this category.
+ *
+ * @param category category name
+ * @return {@code true} if an AID group existed
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
+ public boolean removeDynamicAidGroupForCategory(@NonNull String category) {
return (mDynamicAidGroups.remove(category) != null);
}
@@ -403,7 +469,9 @@
* for that category.
* @return List of AIDs registered by the service
*/
- public ArrayList<AidGroup> getAidGroups() {
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
+ public List<AidGroup> getAidGroups() {
final ArrayList<AidGroup> groups = new ArrayList<AidGroup>();
for (Map.Entry<String, AidGroup> entry : mDynamicAidGroups.entrySet()) {
groups.add(entry.getValue());
@@ -421,49 +489,83 @@
/**
* Returns the category to which this service has attributed the AID that is passed in,
* or null if we don't know this AID.
+ * @param aid AID to lookup for
+ * @return category name corresponding to this AID
*/
- public String getCategoryForAid(String aid) {
- ArrayList<AidGroup> groups = getAidGroups();
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
+ public String getCategoryForAid(@NonNull String aid) {
+ List<AidGroup> groups = getAidGroups();
for (AidGroup group : groups) {
- if (group.aids.contains(aid.toUpperCase())) {
- return group.category;
+ if (group.getAids().contains(aid.toUpperCase())) {
+ return group.getCategory();
}
}
return null;
}
- public boolean hasCategory(String category) {
+ /**
+ * Returns whether there is any AID group for this category.
+ * @param category category name
+ * @return {@code true} if an AID group exists
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ public boolean hasCategory(@NonNull String category) {
return (mStaticAidGroups.containsKey(category) || mDynamicAidGroups.containsKey(category));
}
- @UnsupportedAppUsage
+ /**
+ * Returns whether the service is on host or not.
+ * @return true if the service is on host (not secure element)
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
public boolean isOnHost() {
return mOnHost;
}
- @UnsupportedAppUsage
+ /**
+ * Returns whether the service requires device unlock.
+ * @return whether the service requires device unlock
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
public boolean requiresUnlock() {
return mRequiresDeviceUnlock;
}
/**
* Returns whether this service should only be started when the device is screen on.
+ * @return whether the service requires screen on
*/
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
public boolean requiresScreenOn() {
return mRequiresDeviceScreenOn;
}
- @UnsupportedAppUsage
+ /**
+ * Returns description of service.
+ * @return user readable description of service
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
public String getDescription() {
return mDescription;
}
- @UnsupportedAppUsage
+ /**
+ * Returns uid of service.
+ * @return uid of the service
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
public int getUid() {
return mUid;
}
- public void setOrReplaceDynamicAidGroup(AidGroup aidGroup) {
+ /**
+ * Add or replace an AID group to this service.
+ * @param aidGroup instance of aid group to set or replace
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ public void setDynamicAidGroup(@NonNull AidGroup aidGroup) {
mDynamicAidGroups.put(aidGroup.getCategory(), aidGroup);
}
@@ -476,7 +578,8 @@
* TS26_NFC_REQ_070: For embedded SE, Secure Element Name SHALL be eSE[number]
* (e.g. eSE/eSE1, eSE2, etc.).
*/
- public void setOffHostSecureElement(String offHost) {
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ public void setOffHostSecureElement(@NonNull String offHost) {
mOffHostName = offHost;
}
@@ -484,15 +587,30 @@
* Resets the off host Secure Element to statically defined
* by the service in the manifest file.
*/
- public void unsetOffHostSecureElement() {
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ public void resetOffHostSecureElement() {
mOffHostName = mStaticOffHostName;
}
- public CharSequence loadLabel(PackageManager pm) {
+ /**
+ * Load label for this service.
+ * @param pm packagemanager instance
+ * @return label name corresponding to service
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
+ public CharSequence loadLabel(@NonNull PackageManager pm) {
return mService.loadLabel(pm);
}
- public CharSequence loadAppLabel(PackageManager pm) {
+ /**
+ * Load application label for this service.
+ * @param pm packagemanager instance
+ * @return app label name corresponding to service
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
+ public CharSequence loadAppLabel(@NonNull PackageManager pm) {
try {
return pm.getApplicationLabel(pm.getApplicationInfo(
mService.resolvePackageName, PackageManager.GET_META_DATA));
@@ -501,12 +619,25 @@
}
}
- public Drawable loadIcon(PackageManager pm) {
+ /**
+ * Load application icon for this service.
+ * @param pm packagemanager instance
+ * @return app icon corresponding to service
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
+ public Drawable loadIcon(@NonNull PackageManager pm) {
return mService.loadIcon(pm);
}
- @UnsupportedAppUsage
- public Drawable loadBanner(PackageManager pm) {
+ /**
+ * Load application banner for this service.
+ * @param pm packagemanager instance
+ * @return app banner corresponding to service
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
+ public Drawable loadBanner(@NonNull PackageManager pm) {
Resources res;
try {
res = pm.getResourcesForApplication(mService.serviceInfo.packageName);
@@ -521,7 +652,12 @@
}
}
- @UnsupportedAppUsage
+ /**
+ * Load activity name for this service.
+ * @return activity name for this service
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
public String getSettingsActivityName() { return mSettingsActivityName; }
@Override
@@ -556,14 +692,15 @@
return getComponent().hashCode();
}
-
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
@Override
public int describeContents() {
return 0;
}
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
mService.writeToParcel(dest, flags);
dest.writeString(mDescription);
dest.writeInt(mOnHost ? 1 : 0);
@@ -584,8 +721,8 @@
dest.writeString(mSettingsActivityName);
};
- @UnsupportedAppUsage
- public static final @android.annotation.NonNull Parcelable.Creator<ApduServiceInfo> CREATOR =
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ public static final @NonNull Parcelable.Creator<ApduServiceInfo> CREATOR =
new Parcelable.Creator<ApduServiceInfo>() {
@Override
public ApduServiceInfo createFromParcel(Parcel source) {
@@ -620,7 +757,15 @@
}
};
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ /**
+ * Dump contents for debugging.
+ * @param fd parcelfiledescriptor instance
+ * @param pw printwriter instance
+ * @param args args for dumping
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ public void dump(@NonNull ParcelFileDescriptor fd, @NonNull PrintWriter pw,
+ @NonNull String[] args) {
pw.println(" " + getComponent()
+ " (Description: " + getDescription() + ")"
+ " (UID: " + getUid() + ")");
@@ -633,15 +778,15 @@
}
pw.println(" Static AID groups:");
for (AidGroup group : mStaticAidGroups.values()) {
- pw.println(" Category: " + group.category);
- for (String aid : group.aids) {
+ pw.println(" Category: " + group.getCategory());
+ for (String aid : group.getAids()) {
pw.println(" AID: " + aid);
}
}
pw.println(" Dynamic AID groups:");
for (AidGroup group : mDynamicAidGroups.values()) {
- pw.println(" Category: " + group.category);
- for (String aid : group.aids) {
+ pw.println(" Category: " + group.getCategory());
+ for (String aid : group.getAids()) {
pw.println(" AID: " + aid);
}
}
@@ -651,7 +796,7 @@
}
/**
- * Dump debugging info as ApduServiceInfoProto
+ * Dump debugging info as ApduServiceInfoProto.
*
* If the output belongs to a sub message, the caller is responsible for wrapping this function
* between {@link ProtoOutputStream#start(long)} and {@link ProtoOutputStream#end(long)}.
@@ -659,7 +804,8 @@
*
* @param proto the ProtoOutputStream to write to
*/
- public void dumpDebug(ProtoOutputStream proto) {
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ public void dumpDebug(@NonNull ProtoOutputStream proto) {
Utils.dumpDebugComponentName(getComponent(), proto, ApduServiceInfoProto.COMPONENT_NAME);
proto.write(ApduServiceInfoProto.DESCRIPTION, getDescription());
proto.write(ApduServiceInfoProto.ON_HOST, mOnHost);
diff --git a/core/java/android/nfc/cardemulation/NfcFServiceInfo.java b/core/java/android/nfc/cardemulation/NfcFServiceInfo.java
index 7a36b26..ec919e4 100644
--- a/core/java/android/nfc/cardemulation/NfcFServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/NfcFServiceInfo.java
@@ -14,9 +14,16 @@
* limitations under the License.
*/
+/**********************************************************************
+ * This file is not a part of the NFC mainline module *
+ * *******************************************************************/
+
package android.nfc.cardemulation;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -26,7 +33,9 @@
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
+import android.nfc.Flags;
import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
@@ -36,13 +45,16 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
/**
+ * Class to hold NfcF service info.
+ *
* @hide
*/
+@SystemApi
+@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
public final class NfcFServiceInfo implements Parcelable {
static final String TAG = "NfcFServiceInfo";
@@ -51,42 +63,42 @@
/**
* The service that implements this
*/
- final ResolveInfo mService;
+ private final ResolveInfo mService;
/**
* Description of the service
*/
- final String mDescription;
+ private final String mDescription;
/**
* System Code of the service
*/
- final String mSystemCode;
+ private final String mSystemCode;
/**
* System Code of the service registered by API
*/
- String mDynamicSystemCode;
+ private String mDynamicSystemCode;
/**
* NFCID2 of the service
*/
- final String mNfcid2;
+ private final String mNfcid2;
/**
* NFCID2 of the service registered by API
*/
- String mDynamicNfcid2;
+ private String mDynamicNfcid2;
/**
* The uid of the package the service belongs to
*/
- final int mUid;
+ private final int mUid;
/**
* LF_T3T_PMM of the service
*/
- final String mT3tPmm;
+ private final String mT3tPmm;
/**
* @hide
@@ -104,7 +116,16 @@
this.mT3tPmm = t3tPmm;
}
- public NfcFServiceInfo(PackageManager pm, ResolveInfo info)
+ /**
+ * Creates a new NfcFServiceInfo object.
+ *
+ * @param pm packageManager instance
+ * @param info app component info
+ * @throws XmlPullParserException If an error occurs parsing the element.
+ * @throws IOException If an error occurs reading the element.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ public NfcFServiceInfo(@NonNull PackageManager pm, @NonNull ResolveInfo info)
throws XmlPullParserException, IOException {
ServiceInfo si = info.serviceInfo;
XmlResourceParser parser = null;
@@ -192,44 +213,107 @@
mUid = si.applicationInfo.uid;
}
+ /**
+ * Returns the app component corresponding to this NFCF service.
+ *
+ * @return app component for this service
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
public ComponentName getComponent() {
return new ComponentName(mService.serviceInfo.packageName,
mService.serviceInfo.name);
}
+ /**
+ * Returns the system code corresponding to this service.
+ *
+ * @return system code for this service
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
public String getSystemCode() {
return (mDynamicSystemCode == null ? mSystemCode : mDynamicSystemCode);
}
- public void setOrReplaceDynamicSystemCode(String systemCode) {
+ /**
+ * Add or replace a system code to this service.
+ * @param systemCode system code to set or replace
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ public void setDynamicSystemCode(@NonNull String systemCode) {
mDynamicSystemCode = systemCode;
}
+ /**
+ * Returns NFC ID2.
+ *
+ * @return nfc id2 to return
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
public String getNfcid2() {
return (mDynamicNfcid2 == null ? mNfcid2 : mDynamicNfcid2);
}
- public void setOrReplaceDynamicNfcid2(String nfcid2) {
+ /**
+ * Set or replace NFC ID2
+ *
+ * @param nfcid2 NFC ID2 string
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ public void setDynamicNfcid2(@NonNull String nfcid2) {
mDynamicNfcid2 = nfcid2;
}
+ /**
+ * Returns description of service.
+ * @return user readable description of service
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
public String getDescription() {
return mDescription;
}
+ /**
+ * Returns uid of service.
+ * @return uid of the service
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
public int getUid() {
return mUid;
}
+ /**
+ * Returns LF_T3T_PMM of the service
+ * @return returns LF_T3T_PMM of the service
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
public String getT3tPmm() {
return mT3tPmm;
}
- public CharSequence loadLabel(PackageManager pm) {
+ /**
+ * Load application label for this service.
+ * @param pm packagemanager instance
+ * @return label name corresponding to service
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
+ public CharSequence loadLabel(@NonNull PackageManager pm) {
return mService.loadLabel(pm);
}
- public Drawable loadIcon(PackageManager pm) {
+ /**
+ * Load application icon for this service.
+ * @param pm packagemanager instance
+ * @return app icon corresponding to service
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
+ public Drawable loadIcon(@NonNull PackageManager pm) {
return mService.loadIcon(pm);
}
@@ -270,13 +354,15 @@
return getComponent().hashCode();
}
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
@Override
public int describeContents() {
return 0;
}
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
mService.writeToParcel(dest, flags);
dest.writeString(mDescription);
dest.writeString(mSystemCode);
@@ -293,7 +379,8 @@
dest.writeString(mT3tPmm);
};
- public static final @android.annotation.NonNull Parcelable.Creator<NfcFServiceInfo> CREATOR =
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ public static final @NonNull Parcelable.Creator<NfcFServiceInfo> CREATOR =
new Parcelable.Creator<NfcFServiceInfo>() {
@Override
public NfcFServiceInfo createFromParcel(Parcel source) {
@@ -322,7 +409,15 @@
}
};
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ /**
+ * Dump contents of the service for debugging.
+ * @param fd parcelfiledescriptor instance
+ * @param pw printwriter instance
+ * @param args args for dumping
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ public void dump(@NonNull ParcelFileDescriptor fd, @NonNull PrintWriter pw,
+ @NonNull String[] args) {
pw.println(" " + getComponent()
+ " (Description: " + getDescription() + ")"
+ " (UID: " + getUid() + ")");
@@ -332,14 +427,15 @@
}
/**
- * Dump debugging info as NfcFServiceInfoProto
+ * Dump debugging info as NfcFServiceInfoProto.
*
* If the output belongs to a sub message, the caller is responsible for wrapping this function
* between {@link ProtoOutputStream#start(long)} and {@link ProtoOutputStream#end(long)}.
*
* @param proto the ProtoOutputStream to write to
*/
- public void dumpDebug(ProtoOutputStream proto) {
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ public void dumpDebug(@NonNull ProtoOutputStream proto) {
Utils.dumpDebugComponentName(getComponent(), proto, NfcFServiceInfoProto.COMPONENT_NAME);
proto.write(NfcFServiceInfoProto.DESCRIPTION, getDescription());
proto.write(NfcFServiceInfoProto.SYSTEM_CODE, getSystemCode());
@@ -347,4 +443,3 @@
proto.write(NfcFServiceInfoProto.T3T_PMM, getT3tPmm());
}
}
-
diff --git a/core/java/android/nfc/flags.aconfig b/core/java/android/nfc/flags.aconfig
new file mode 100644
index 0000000..e3faf39
--- /dev/null
+++ b/core/java/android/nfc/flags.aconfig
@@ -0,0 +1,8 @@
+package: "android.nfc"
+
+flag {
+ name: "enable_nfc_mainline"
+ namespace: "nfc"
+ description: "Flag for NFC mainline changes"
+ bug: "292140387"
+}
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index 1929a4d..5196b17 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -32,7 +32,9 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -613,15 +615,35 @@
*/
public native boolean transactNative(int code, Parcel data, Parcel reply,
int flags) throws RemoteException;
+
+ /* This list is to hold strong reference to the death recipients that are waiting for the death
+ * of binder that this proxy references. Previously, the death recipients were strongy
+ * referenced from JNI, but that can cause memory leak (b/298374304) when the application has a
+ * strong reference from the death recipient to the proxy object. The JNI reference is now weak.
+ * And this strong reference is to keep death recipients at least until the proxy is GC'ed. */
+ private List<DeathRecipient> mDeathRecipients = Collections.synchronizedList(new ArrayList<>());
+
/**
* See {@link IBinder#linkToDeath(DeathRecipient, int)}
*/
- public native void linkToDeath(DeathRecipient recipient, int flags)
- throws RemoteException;
+ public void linkToDeath(DeathRecipient recipient, int flags)
+ throws RemoteException {
+ linkToDeathNative(recipient, flags);
+ mDeathRecipients.add(recipient);
+ }
+
/**
* See {@link IBinder#unlinkToDeath}
*/
- public native boolean unlinkToDeath(DeathRecipient recipient, int flags);
+ public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
+ mDeathRecipients.remove(recipient);
+ return unlinkToDeathNative(recipient, flags);
+ }
+
+ private native void linkToDeathNative(DeathRecipient recipient, int flags)
+ throws RemoteException;
+
+ private native boolean unlinkToDeathNative(DeathRecipient recipient, int flags);
/**
* Perform a dump on the remote object
diff --git a/core/java/com/android/internal/net/OWNERS b/core/java/com/android/internal/net/OWNERS
index 71f997b..7157683 100644
--- a/core/java/com/android/internal/net/OWNERS
+++ b/core/java/com/android/internal/net/OWNERS
@@ -1,4 +1,4 @@
set noparent
-file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
+file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking
jsharkey@android.com
diff --git a/core/java/com/android/server/net/OWNERS b/core/java/com/android/server/net/OWNERS
index 62c5737..c24680e9 100644
--- a/core/java/com/android/server/net/OWNERS
+++ b/core/java/com/android/server/net/OWNERS
@@ -1,2 +1,2 @@
set noparent
-file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
+file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 73c93ac..81c3255 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -15,7 +15,19 @@
],
}
-cc_library_shared {
+soong_config_module_type {
+ name: "cc_library_shared_for_libandroid_runtime",
+ module_type: "cc_library_shared",
+ config_namespace: "ANDROID",
+ bool_variables: [
+ "release_binder_death_recipient_weak_from_jni",
+ ],
+ properties: [
+ "cflags",
+ ],
+}
+
+cc_library_shared_for_libandroid_runtime {
name: "libandroid_runtime",
host_supported: true,
cflags: [
@@ -46,6 +58,12 @@
},
},
+ soong_config_variables: {
+ release_binder_death_recipient_weak_from_jni: {
+ cflags: ["-DBINDER_DEATH_RECIPIENT_WEAK_FROM_JNI"],
+ },
+ },
+
cpp_std: "gnu++20",
srcs: [
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 6ed0a8a..55382cc 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -17,19 +17,8 @@
#define LOG_TAG "JavaBinder"
//#define LOG_NDEBUG 0
-#include "android_os_Parcel.h"
#include "android_util_Binder.h"
-#include <atomic>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <mutex>
-#include <stdio.h>
-#include <string>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
#include <android-base/stringprintf.h>
#include <binder/BpBinder.h>
#include <binder/IInterface.h>
@@ -40,7 +29,16 @@
#include <binder/Stability.h>
#include <binderthreadstate/CallerUtils.h>
#include <cutils/atomic.h>
+#include <fcntl.h>
+#include <inttypes.h>
#include <log/log.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedUtfChars.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <utils/KeyedVector.h>
#include <utils/List.h>
#include <utils/Log.h>
@@ -48,10 +46,11 @@
#include <utils/SystemClock.h>
#include <utils/threads.h>
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedLocalRef.h>
-#include <nativehelper/ScopedUtfChars.h>
+#include <atomic>
+#include <mutex>
+#include <string>
+#include "android_os_Parcel.h"
#include "core_jni_helpers.h"
//#undef ALOGV
@@ -557,14 +556,48 @@
};
// ----------------------------------------------------------------------------
+#ifdef BINDER_DEATH_RECIPIENT_WEAK_FROM_JNI
+#if __BIONIC__
+#include <android/api-level.h>
+static bool target_sdk_is_at_least_vic() {
+ return android_get_application_target_sdk_version() >= __ANDROID_API_V__;
+}
+#else
+static constexpr bool target_sdk_is_at_least_vic() {
+ // If not built for Android (i.e. glibc host), follow the latest behavior as there's no compat
+ // requirement there.
+ return true;
+}
+#endif // __BIONIC__
+#endif // BINDER_DEATH_RECIPIENT_WEAK_FROM_JNI
class JavaDeathRecipient : public IBinder::DeathRecipient
{
public:
JavaDeathRecipient(JNIEnv* env, jobject object, const sp<DeathRecipientList>& list)
- : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)),
- mObjectWeak(NULL), mList(list)
- {
+ : mVM(jnienv_to_javavm(env)), mObject(NULL), mObjectWeak(NULL), mList(list) {
+ // b/298374304: For apps targeting Android V or beyond, we no longer hold the global JNI ref
+ // to the death recipient objects. This is to prevent the memory leak which can happen when
+ // the death recipient object internally has a strong reference to the proxy object. Under
+ // the old behavior, you were unable to kill the binder service by dropping all references
+ // to the proxy object - because it is still strong referenced from JNI (here). The only way
+ // to cut the strong reference was to call unlinkDeath(), but it was easy to forget.
+ //
+ // Now, the strong reference to the death recipient is held in the Java-side proxy object.
+ // See BinderProxy.mDeathRecipients. From JNI, only the weak reference is kept. An
+ // implication of this is that you may not receive binderDied() if you drop all references
+ // to the proxy object before the service dies. This should be okay for most cases because
+ // you normally are not interested in the death of a binder service which you don't have any
+ // reference to. If however you want to get binderDied() regardless of the proxy object's
+ // lifecycle, keep a strong reference to the death recipient object by yourself.
+#ifdef BINDER_DEATH_RECIPIENT_WEAK_FROM_JNI
+ if (target_sdk_is_at_least_vic()) {
+ mObjectWeak = env->NewWeakGlobalRef(object);
+ } else
+#endif
+ {
+ mObject = env->NewGlobalRef(object);
+ }
// These objects manage their own lifetimes so are responsible for final bookkeeping.
// The list holds a strong reference to this object.
LOGDEATH("Adding JDR %p to DRL %p", this, list.get());
@@ -577,26 +610,49 @@
void binderDied(const wp<IBinder>& who)
{
LOGDEATH("Receiving binderDied() on JavaDeathRecipient %p\n", this);
- if (mObject != NULL) {
- JNIEnv* env = javavm_to_jnienv(mVM);
- ScopedLocalRef<jobject> jBinderProxy(env, javaObjectForIBinder(env, who.promote()));
- env->CallStaticVoidMethod(gBinderProxyOffsets.mClass,
- gBinderProxyOffsets.mSendDeathNotice, mObject,
- jBinderProxy.get());
- if (env->ExceptionCheck()) {
- jthrowable excep = env->ExceptionOccurred();
- binder_report_exception(env, excep,
- "*** Uncaught exception returned from death notification!");
- }
+ if (mObject == NULL && mObjectWeak == NULL) {
+ return;
+ }
+ JNIEnv* env = javavm_to_jnienv(mVM);
+ ScopedLocalRef<jobject> jBinderProxy(env, javaObjectForIBinder(env, who.promote()));
- // Serialize with our containing DeathRecipientList so that we can't
- // delete the global ref on mObject while the list is being iterated.
+ // Hold a local reference to the recipient. This may fail if the recipient is weakly
+ // referenced, in which case we can't deliver the death notice.
+ ScopedLocalRef<jobject> jRecipient(env,
+ env->NewLocalRef(mObject != NULL ? mObject
+ : mObjectWeak));
+ if (jRecipient.get() == NULL) {
+ ALOGW("Binder died, but death recipient is already garbage collected. If your target "
+ "sdk level is at or above 35, this can happen when you dropped all references to "
+ "the binder service before it died. If you want to get a death notice for a "
+ "binder service which you have no reference to, keep a strong reference to the "
+ "death recipient by yourself.");
+ return;
+ }
+
+ if (mFired) {
+ ALOGW("Received multiple death notices for the same binder object. Binder driver bug?");
+ return;
+ }
+ mFired = true;
+
+ env->CallStaticVoidMethod(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mSendDeathNotice,
+ jRecipient.get(), jBinderProxy.get());
+ if (env->ExceptionCheck()) {
+ jthrowable excep = env->ExceptionOccurred();
+ binder_report_exception(env, excep,
+ "*** Uncaught exception returned from death notification!");
+ }
+
+ // Demote from strong ref (if exists) to weak after binderDied() has been delivered, to
+ // allow the DeathRecipient and BinderProxy to be GC'd if no longer needed. Do this in sync
+ // with our containing DeathRecipientList so that we can't delete the global ref on mObject
+ // while the list is being iterated.
+ if (mObject != NULL) {
sp<DeathRecipientList> list = mList.promote();
if (list != NULL) {
AutoMutex _l(list->lock());
- // Demote from strong ref to weak after binderDied() has been delivered,
- // to allow the DeathRecipient and BinderProxy to be GC'd if no longer needed.
mObjectWeak = env->NewWeakGlobalRef(mObject);
env->DeleteGlobalRef(mObject);
mObject = NULL;
@@ -663,9 +719,19 @@
private:
JavaVM* const mVM;
- jobject mObject; // Initial strong ref to Java-side DeathRecipient. Cleared on binderDied().
- jweak mObjectWeak; // Weak ref to the same Java-side DeathRecipient after binderDied().
+
+ // If target sdk version < 35, the Java-side DeathRecipient is strongly referenced from mObject
+ // upon linkToDeath() and then after binderDied() is called, the strong reference is demoted to
+ // a weak reference (mObjectWeak).
+ // If target sdk version >= 35, the strong reference is never made here (i.e. mObject == NULL
+ // always). Instead, the strong reference to the Java-side DeathRecipient is made in
+ // BinderProxy.mDeathRecipients. In the native world, only the weak reference is kept.
+ jobject mObject;
+ jweak mObjectWeak;
wp<DeathRecipientList> mList;
+
+ // Whether binderDied was called or not.
+ bool mFired = false;
};
// ----------------------------------------------------------------------------
@@ -1452,17 +1518,19 @@
// ----------------------------------------------------------------------------
+// clang-format off
static const JNINativeMethod gBinderProxyMethods[] = {
/* name, signature, funcPtr */
{"pingBinder", "()Z", (void*)android_os_BinderProxy_pingBinder},
{"isBinderAlive", "()Z", (void*)android_os_BinderProxy_isBinderAlive},
{"getInterfaceDescriptor", "()Ljava/lang/String;", (void*)android_os_BinderProxy_getInterfaceDescriptor},
{"transactNative", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
- {"linkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
- {"unlinkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
+ {"linkToDeathNative", "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
+ {"unlinkToDeathNative", "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
{"getNativeFinalizer", "()J", (void*)android_os_BinderProxy_getNativeFinalizer},
{"getExtension", "()Landroid/os/IBinder;", (void*)android_os_BinderProxy_getExtension},
};
+// clang-format on
const char* const kBinderProxyPathName = "android/os/BinderProxy";
diff --git a/core/tests/fuzzers/ParcelFuzzer/ReadUtils.java b/core/tests/fuzzers/ParcelFuzzer/ReadUtils.java
index b5e5b25..cb98855 100644
--- a/core/tests/fuzzers/ParcelFuzzer/ReadUtils.java
+++ b/core/tests/fuzzers/ParcelFuzzer/ReadUtils.java
@@ -364,6 +364,12 @@
TestClassLoader loader = new TestClassLoader();
parcel.readParcelableArray(loader);
},
+ (parcel, provider) -> {
+ parcel.readParcelable(null);
+ },
+ (parcel, provider) -> {
+ parcel.readParcelableArray(null);
+ },
// read lists
(parcel, provider) -> {
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 9eed904..6db1832 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -16,6 +16,7 @@
package android.security.keystore;
+import android.annotation.FlaggedApi;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -34,7 +35,10 @@
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.spec.AlgorithmParameterSpec;
+import java.util.Collections;
import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
@@ -300,6 +304,7 @@
private final Date mKeyValidityForConsumptionEnd;
private final @KeyProperties.PurposeEnum int mPurposes;
private final @KeyProperties.DigestEnum String[] mDigests;
+ private final @NonNull @KeyProperties.DigestEnum Set<String> mMgf1Digests;
private final @KeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
private final @KeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
private final @KeyProperties.BlockModeEnum String[] mBlockModes;
@@ -343,6 +348,7 @@
Date keyValidityForConsumptionEnd,
@KeyProperties.PurposeEnum int purposes,
@KeyProperties.DigestEnum String[] digests,
+ @KeyProperties.DigestEnum Set<String> mgf1Digests,
@KeyProperties.EncryptionPaddingEnum String[] encryptionPaddings,
@KeyProperties.SignaturePaddingEnum String[] signaturePaddings,
@KeyProperties.BlockModeEnum String[] blockModes,
@@ -401,6 +407,9 @@
mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
mPurposes = purposes;
mDigests = ArrayUtils.cloneIfNotEmpty(digests);
+ // No need to copy the input parameter because the Builder class passes in an immutable
+ // collection.
+ mMgf1Digests = mgf1Digests != null ? mgf1Digests : Collections.emptySet();
mEncryptionPaddings =
ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
@@ -562,7 +571,7 @@
/**
* Returns the set of digest algorithms (e.g., {@code SHA-256}, {@code SHA-384} with which the
- * key can be used or {@code null} if not specified.
+ * key can be used.
*
* <p>See {@link KeyProperties}.{@code DIGEST} constants.
*
@@ -590,6 +599,40 @@
}
/**
+ * Returns the set of digests that can be used by the MGF1 mask generation function
+ * (e.g., {@code SHA-256}, {@code SHA-384}) with the key. Useful with the {@code RSA-OAEP}
+ * scheme.
+ * If not explicitly specified during key generation, the default {@code SHA-1} digest is
+ * used and may be specified when using the key.
+ *
+ * <p>See {@link KeyProperties}.{@code DIGEST} constants.
+ *
+ * @throws IllegalStateException if this set has not been specified.
+ *
+ * @see #isMgf1DigestsSpecified()
+ */
+ @NonNull
+ @FlaggedApi("MGF1_DIGEST_SETTER")
+ public @KeyProperties.DigestEnum Set<String> getMgf1Digests() {
+ if (mMgf1Digests.isEmpty()) {
+ throw new IllegalStateException("Mask generation function (MGF) not specified");
+ }
+ return new HashSet(mMgf1Digests);
+ }
+
+ /**
+ * Returns {@code true} if the set of digests for the MGF1 mask generation function,
+ * with which the key can be used, has been specified. Useful with the {@code RSA-OAEP} scheme.
+ *
+ * @see #getMgf1Digests()
+ */
+ @NonNull
+ @FlaggedApi("MGF1_DIGEST_SETTER")
+ public boolean isMgf1DigestsSpecified() {
+ return !mMgf1Digests.isEmpty();
+ }
+
+ /**
* Returns the set of padding schemes (e.g., {@code PKCS7Padding}, {@code OEAPPadding},
* {@code PKCS1Padding}, {@code NoPadding}) with which the key can be used when
* encrypting/decrypting. Attempts to use the key with any other padding scheme will be
@@ -899,6 +942,8 @@
private Date mKeyValidityForOriginationEnd;
private Date mKeyValidityForConsumptionEnd;
private @KeyProperties.DigestEnum String[] mDigests;
+ private @NonNull @KeyProperties.DigestEnum Set<String> mMgf1Digests =
+ Collections.emptySet();
private @KeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
private @KeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
private @KeyProperties.BlockModeEnum String[] mBlockModes;
@@ -968,6 +1013,9 @@
if (sourceSpec.isDigestsSpecified()) {
mDigests = sourceSpec.getDigests();
}
+ if (sourceSpec.isMgf1DigestsSpecified()) {
+ mMgf1Digests = sourceSpec.getMgf1Digests();
+ }
mEncryptionPaddings = sourceSpec.getEncryptionPaddings();
mSignaturePaddings = sourceSpec.getSignaturePaddings();
mBlockModes = sourceSpec.getBlockModes();
@@ -1214,6 +1262,30 @@
}
/**
+ * Sets the set of hash functions (e.g., {@code SHA-256}, {@code SHA-384}) which could be
+ * used by the mask generation function MGF1 (which is used for certain operations with
+ * the key). Attempts to use the key with any other digest for the mask generation
+ * function will be rejected.
+ *
+ * <p>This can only be specified for signing/verification keys and RSA encryption/decryption
+ * keys used with RSA OAEP padding scheme because these operations involve a mask generation
+ * function (MGF1) with a digest.
+ * The default digest for MGF1 is {@code SHA-1}, which will be specified during key creation
+ * time if no digests have been explicitly provided.
+ * When using the key, the caller may not specify any digests that were not provided during
+ * key creation time. The caller may specify the default digest, {@code SHA-1}, if no
+ * digests were explicitly provided during key creation (but it is not necessary to do so).
+ *
+ * <p>See {@link KeyProperties}.{@code DIGEST} constants.
+ */
+ @NonNull
+ @FlaggedApi("MGF1_DIGEST_SETTER")
+ public Builder setMgf1Digests(@Nullable @KeyProperties.DigestEnum String... mgf1Digests) {
+ mMgf1Digests = Set.of(mgf1Digests);
+ return this;
+ }
+
+ /**
* Sets the set of padding schemes (e.g., {@code PKCS7Padding}, {@code OAEPPadding},
* {@code PKCS1Padding}, {@code NoPadding}) with which the key can be used when
* encrypting/decrypting. Attempts to use the key with any other padding scheme will be
@@ -1745,6 +1817,7 @@
mKeyValidityForConsumptionEnd,
mPurposes,
mDigests,
+ mMgf1Digests,
mEncryptionPaddings,
mSignaturePaddings,
mBlockModes,
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index c14c3c5..1262a53 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -16,6 +16,7 @@
package android.security.keystore;
+import android.annotation.FlaggedApi;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -30,7 +31,10 @@
import java.security.KeyStore.ProtectionParameter;
import java.security.Signature;
import java.security.cert.Certificate;
+import java.util.Collections;
import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
import javax.crypto.Cipher;
import javax.crypto.Mac;
@@ -223,6 +227,7 @@
private final @KeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
private final @KeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
private final @KeyProperties.DigestEnum String[] mDigests;
+ private final @NonNull @KeyProperties.DigestEnum Set<String> mMgf1Digests;
private final @KeyProperties.BlockModeEnum String[] mBlockModes;
private final boolean mRandomizedEncryptionRequired;
private final boolean mUserAuthenticationRequired;
@@ -246,6 +251,7 @@
@KeyProperties.EncryptionPaddingEnum String[] encryptionPaddings,
@KeyProperties.SignaturePaddingEnum String[] signaturePaddings,
@KeyProperties.DigestEnum String[] digests,
+ @KeyProperties.DigestEnum Set<String> mgf1Digests,
@KeyProperties.BlockModeEnum String[] blockModes,
boolean randomizedEncryptionRequired,
boolean userAuthenticationRequired,
@@ -269,6 +275,7 @@
mSignaturePaddings =
ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
mDigests = ArrayUtils.cloneIfNotEmpty(digests);
+ mMgf1Digests = mgf1Digests;
mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
mRandomizedEncryptionRequired = randomizedEncryptionRequired;
mUserAuthenticationRequired = userAuthenticationRequired;
@@ -378,6 +385,40 @@
}
/**
+ * Returns the set of digests that can be used by the MGF1 mask generation function
+ * (e.g., {@code SHA-256}, {@code SHA-384}) with the key. Useful with the {@code RSA-OAEP}
+ * scheme.
+ * If not explicitly specified during key generation, the default {@code SHA-1} digest is
+ * used and may be specified.
+ *
+ * <p>See {@link KeyProperties}.{@code DIGEST} constants.
+ *
+ * @throws IllegalStateException if this set has not been specified.
+ *
+ * @see #isMgf1DigestsSpecified()
+ */
+ @NonNull
+ @FlaggedApi("MGF1_DIGEST_SETTER")
+ public @KeyProperties.DigestEnum Set<String> getMgf1Digests() {
+ if (mMgf1Digests.isEmpty()) {
+ throw new IllegalStateException("Mask generation function (MGF) not specified");
+ }
+ return new HashSet(mMgf1Digests);
+ }
+
+ /**
+ * Returns {@code true} if the set of digests for the MGF1 mask generation function,
+ * with which the key can be used, has been specified. Useful with the {@code RSA-OAEP} scheme.
+ *
+ * @see #getMgf1Digests()
+ */
+ @NonNull
+ @FlaggedApi("MGF1_DIGEST_SETTER")
+ public boolean isMgf1DigestsSpecified() {
+ return !mMgf1Digests.isEmpty();
+ }
+
+ /**
* Gets the set of block modes (e.g., {@code GCM}, {@code CBC}) with which the key can be used
* when encrypting/decrypting. Attempts to use the key with any other block modes will be
* rejected.
@@ -574,6 +615,8 @@
private @KeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
private @KeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
private @KeyProperties.DigestEnum String[] mDigests;
+ private @NonNull @KeyProperties.DigestEnum Set<String> mMgf1Digests =
+ Collections.emptySet();
private @KeyProperties.BlockModeEnum String[] mBlockModes;
private boolean mRandomizedEncryptionRequired = true;
private boolean mUserAuthenticationRequired;
@@ -724,6 +767,30 @@
}
/**
+ * Sets the set of hash functions (e.g., {@code SHA-256}, {@code SHA-384}) which could be
+ * used by the mask generation function MGF1 (which is used for certain operations with
+ * the key). Attempts to use the key with any other digest for the mask generation
+ * function will be rejected.
+ *
+ * <p>This can only be specified for signing/verification keys and RSA encryption/decryption
+ * keys used with RSA OAEP padding scheme because these operations involve a mask generation
+ * function (MGF1) with a digest.
+ * The default digest for MGF1 is {@code SHA-1}, which will be specified during key import
+ * time if no digests have been explicitly provided.
+ * When using the key, the caller may not specify any digests that were not provided during
+ * key import time. The caller may specify the default digest, {@code SHA-1}, if no
+ * digests were explicitly provided during key import (but it is not necessary to do so).
+ *
+ * <p>See {@link KeyProperties}.{@code DIGEST} constants.
+ */
+ @NonNull
+ @FlaggedApi("MGF1_DIGEST_SETTER")
+ public Builder setMgf1Digests(@Nullable @KeyProperties.DigestEnum String... mgf1Digests) {
+ mMgf1Digests = Set.of(mgf1Digests);
+ return this;
+ }
+
+ /**
* Sets the set of block modes (e.g., {@code GCM}, {@code CBC}) with which the key can be
* used when encrypting/decrypting. Attempts to use the key with any other block modes will
* be rejected.
@@ -1111,6 +1178,7 @@
mEncryptionPaddings,
mSignaturePaddings,
mDigests,
+ mMgf1Digests,
mBlockModes,
mRandomizedEncryptionRequired,
mUserAuthenticationRequired,
diff --git a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
index a6e3366..30b3b5c 100644
--- a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
@@ -23,7 +23,11 @@
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.RSAKeyGenParameterSpec;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Date;
+import java.util.List;
+import java.util.Set;
import javax.security.auth.x500.X500Principal;
@@ -91,6 +95,11 @@
} else {
out.writeStringArray(null);
}
+ if (mSpec.isMgf1DigestsSpecified()) {
+ out.writeStringList(List.copyOf(mSpec.getMgf1Digests()));
+ } else {
+ out.writeStringList(null);
+ }
out.writeStringArray(mSpec.getEncryptionPaddings());
out.writeStringArray(mSpec.getSignaturePaddings());
out.writeStringArray(mSpec.getBlockModes());
@@ -152,6 +161,7 @@
final Date keyValidityForOriginationEnd = readDateOrNull(in);
final Date keyValidityForConsumptionEnd = readDateOrNull(in);
final String[] digests = in.createStringArray();
+ final ArrayList<String> mgf1Digests = in.createStringArrayList();
final String[] encryptionPaddings = in.createStringArray();
final String[] signaturePaddings = in.createStringArray();
final String[] blockModes = in.createStringArray();
@@ -189,6 +199,7 @@
keyValidityForConsumptionEnd,
purposes,
digests,
+ mgf1Digests != null ? Set.copyOf(mgf1Digests) : Collections.emptySet(),
encryptionPaddings,
signaturePaddings,
blockModes,
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
index 9ac0f6d..101a10e 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
@@ -24,6 +24,7 @@
import android.security.KeyStoreException;
import android.security.KeyStoreOperation;
import android.security.keymaster.KeymasterDefs;
+import android.security.keystore.KeyProperties;
import android.security.keystore.KeyStoreCryptoOperation;
import android.system.keystore2.Authorization;
@@ -71,7 +72,7 @@
*/
abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStoreCryptoOperation {
private static final String TAG = "AndroidKeyStoreCipherSpiBase";
- public static final String DEFAULT_MGF1_DIGEST = "SHA-1";
+ public static final String DEFAULT_MGF1_DIGEST = KeyProperties.DIGEST_SHA1;
// Fields below are populated by Cipher.init and KeyStore.begin and should be preserved after
// doFinal finishes.
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index 1398da3..ed4b485 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -188,6 +188,7 @@
private int[] mKeymasterEncryptionPaddings;
private int[] mKeymasterSignaturePaddings;
private int[] mKeymasterDigests;
+ private int[] mKeymasterMgf1Digests;
private Long mRSAPublicExponent;
@@ -323,6 +324,21 @@
} else {
mKeymasterDigests = EmptyArray.INT;
}
+ if (spec.isMgf1DigestsSpecified()) {
+ // User-specified digests: Add all of them and do _not_ add the SHA-1
+ // digest by default (stick to what the user provided).
+ Set<String> mgfDigests = spec.getMgf1Digests();
+ mKeymasterMgf1Digests = new int[mgfDigests.size()];
+ int offset = 0;
+ for (String digest : mgfDigests) {
+ mKeymasterMgf1Digests[offset] = KeyProperties.Digest.toKeymaster(digest);
+ offset++;
+ }
+ } else {
+ // No user-specified digests: Add the SHA-1 default.
+ mKeymasterMgf1Digests = new int[]{
+ KeyProperties.Digest.toKeymaster(DEFAULT_MGF1_DIGEST)};
+ }
// Check that user authentication related parameters are acceptable. This method
// will throw an IllegalStateException if there are issues (e.g., secure lock screen
@@ -544,6 +560,7 @@
mKeymasterEncryptionPaddings = null;
mKeymasterSignaturePaddings = null;
mKeymasterDigests = null;
+ mKeymasterMgf1Digests = null;
mKeySizeBits = 0;
mSpec = null;
mRSAPublicExponent = null;
@@ -831,24 +848,11 @@
KeymasterDefs.KM_TAG_PADDING, padding
));
if (padding == KeymasterDefs.KM_PAD_RSA_OAEP) {
- final boolean[] hasDefaultMgf1DigestBeenAdded = {false};
- ArrayUtils.forEach(mKeymasterDigests, (digest) -> {
+ ArrayUtils.forEach(mKeymasterMgf1Digests, (mgf1Digest) -> {
params.add(KeyStore2ParameterUtils.makeEnum(
- KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST, digest
+ KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST, mgf1Digest
));
- hasDefaultMgf1DigestBeenAdded[0] |=
- digest.equals(KeyProperties.Digest.toKeymaster(DEFAULT_MGF1_DIGEST));
});
- /* Because of default MGF1 digest is SHA-1. It has to be added in Key
- * characteristics. Otherwise, crypto operations will fail with Incompatible
- * MGF1 digest.
- */
- if (!hasDefaultMgf1DigestBeenAdded[0]) {
- params.add(KeyStore2ParameterUtils.makeEnum(
- KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST,
- KeyProperties.Digest.toKeymaster(DEFAULT_MGF1_DIGEST)
- ));
- }
}
});
ArrayUtils.forEach(mKeymasterSignaturePaddings, (padding) -> {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index eef8179..d3d9701 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -526,25 +526,22 @@
padding
));
if (padding == KeymasterDefs.KM_PAD_RSA_OAEP) {
- if (spec.isDigestsSpecified()) {
- boolean hasDefaultMgf1DigestBeenAdded = false;
- for (String digest : spec.getDigests()) {
+ if (spec.isMgf1DigestsSpecified()) {
+ for (String mgf1Digest : spec.getMgf1Digests()) {
importArgs.add(KeyStore2ParameterUtils.makeEnum(
KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST,
- KeyProperties.Digest.toKeymaster(digest)
+ KeyProperties.Digest.toKeymaster(mgf1Digest)
));
- hasDefaultMgf1DigestBeenAdded |= digest.equals(DEFAULT_MGF1_DIGEST);
}
+ } else {
/* Because of default MGF1 digest is SHA-1. It has to be added in Key
* characteristics. Otherwise, crypto operations will fail with Incompatible
* MGF1 digest.
*/
- if (!hasDefaultMgf1DigestBeenAdded) {
- importArgs.add(KeyStore2ParameterUtils.makeEnum(
- KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST,
- KeyProperties.Digest.toKeymaster(DEFAULT_MGF1_DIGEST)
- ));
- }
+ importArgs.add(KeyStore2ParameterUtils.makeEnum(
+ KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST,
+ KeyProperties.Digest.toKeymaster(DEFAULT_MGF1_DIGEST)
+ ));
}
}
}
diff --git a/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java
index 2ae61ab..d4e2dbc 100644
--- a/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java
+++ b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java
@@ -17,6 +17,7 @@
package android.security;
import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
@@ -101,6 +102,7 @@
assertThat(spec.getKeyValidityForOriginationEnd(), is(KEY_VALIDITY_FOR_ORIG_END));
assertThat(spec.getKeyValidityForConsumptionEnd(), is(KEY_VALIDITY_FOR_CONSUMPTION_END));
assertThat(spec.getDigests(), is(new String[] {DIGEST}));
+ assertThat(spec.isMgf1DigestsSpecified(), is(false));
assertThat(spec.getEncryptionPaddings(), is(new String[] {ENCRYPTION_PADDING}));
assertThat(spec.getSignaturePaddings(), is(new String[] {SIGNATURE_PADDING}));
assertThat(spec.getBlockModes(), is(new String[] {BLOCK_MODE}));
@@ -189,4 +191,19 @@
ECGenParameterSpec parcelSpec = (ECGenParameterSpec) fromParcel.getAlgorithmParameterSpec();
assertEquals(parcelSpec.getName(), ecSpec.getName());
}
+
+ @Test
+ public void testParcelingMgf1Digests() {
+ String[] mgf1Digests =
+ new String[] {KeyProperties.DIGEST_SHA1, KeyProperties.DIGEST_SHA256};
+
+ ParcelableKeyGenParameterSpec spec = new ParcelableKeyGenParameterSpec(
+ new KeyGenParameterSpec.Builder(ALIAS, KEY_PURPOSES)
+ .setMgf1Digests(mgf1Digests)
+ .build());
+ Parcel parcel = parcelForReading(spec);
+ KeyGenParameterSpec fromParcel =
+ ParcelableKeyGenParameterSpec.CREATOR.createFromParcel(parcel).getSpec();
+ assertArrayEquals(fromParcel.getMgf1Digests().toArray(), mgf1Digests);
+ }
}
diff --git a/keystore/tests/src/android/security/keystore/KeyGenParameterSpecTest.java b/keystore/tests/src/android/security/keystore/KeyGenParameterSpecTest.java
index ddbb1d8..da5e8bf 100644
--- a/keystore/tests/src/android/security/keystore/KeyGenParameterSpecTest.java
+++ b/keystore/tests/src/android/security/keystore/KeyGenParameterSpecTest.java
@@ -16,9 +16,12 @@
package android.security.keystore;
+import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertThrows;
import android.security.ParcelableKeyGenParameterSpecTest;
@@ -61,4 +64,54 @@
assertEquals(copiedSpec.getAttestationChallenge(), null);
}
+
+ @Test
+ public void testMgf1DigestsNotSpecifiedByDefault() {
+ KeyGenParameterSpec spec = ParcelableKeyGenParameterSpecTest.configureDefaultSpec();
+ assertThat(spec.isMgf1DigestsSpecified(), is(false));
+ assertThrows(IllegalStateException.class, () -> {
+ spec.getMgf1Digests();
+ });
+ }
+
+ @Test
+ public void testMgf1DigestsCanBeSpecified() {
+ String[] mgf1Digests =
+ new String[] {KeyProperties.DIGEST_SHA1, KeyProperties.DIGEST_SHA256};
+ KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(ALIAS, KEY_PURPOSES)
+ .setMgf1Digests(mgf1Digests)
+ .build();
+ assertThat(spec.isMgf1DigestsSpecified(), is(true));
+ assertThat(spec.getMgf1Digests(), containsInAnyOrder(mgf1Digests));
+
+ KeyGenParameterSpec copiedSpec = new KeyGenParameterSpec.Builder(spec).build();
+ assertThat(copiedSpec.isMgf1DigestsSpecified(), is(true));
+ assertThat(copiedSpec.getMgf1Digests(), containsInAnyOrder(mgf1Digests));
+ }
+
+ @Test
+ public void testMgf1DigestsAreNotModified() {
+ String[] mgf1Digests =
+ new String[] {KeyProperties.DIGEST_SHA1, KeyProperties.DIGEST_SHA256};
+ KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(ALIAS, KEY_PURPOSES)
+ .setMgf1Digests(mgf1Digests);
+
+ KeyGenParameterSpec firstSpec = builder.build();
+ assertArrayEquals(mgf1Digests, firstSpec.getMgf1Digests().toArray());
+
+ String[] otherDigests = new String[] {KeyProperties.DIGEST_SHA224};
+ KeyGenParameterSpec secondSpec = builder.setMgf1Digests(otherDigests).build();
+ assertThat(secondSpec.getMgf1Digests(), containsInAnyOrder(otherDigests));
+
+ // Now check that the first spec created hasn't changed.
+ assertThat(firstSpec.getMgf1Digests(), containsInAnyOrder(mgf1Digests));
+ }
+
+ @Test
+ public void testEmptyMgf1DigestsCanBeSet() {
+ KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(ALIAS, KEY_PURPOSES)
+ .setMgf1Digests(new String[] {}).build();
+
+ assertThat(spec.isMgf1DigestsSpecified(), is(false));
+ }
}
diff --git a/mime/Android.bp b/mime/Android.bp
index a3ea65c..757862b 100644
--- a/mime/Android.bp
+++ b/mime/Android.bp
@@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
@@ -125,6 +124,6 @@
srcs: [
"java-res/vendor.mime.types",
],
- // strip comments normalize whitepace drop empty lines prepend ? to fields that are missing it
- cmd: "awk '{gsub(/#.*$$/,\"\"); $$1=$$1; print;}' $(in) | grep ' ' | awk '{for(i=1;i<=NF;i++) { sub(/^\\??/, \"?\", $$i); }; print}' > $(out)",
+ // strip comments normalize whitepace drop empty lines prepend ? to fields that are missing it
+ cmd: "awk '{gsub(/#.*$$/,\"\"); $$1=$$1; print;}' $(in) | (grep ' ' || echo -n '') | awk '{for(i=1;i<=NF;i++) { sub(/^\\??/, \"?\", $$i); }; print}' > $(out)",
}
diff --git a/services/Android.bp b/services/Android.bp
index eb56c25..5b15392f 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -255,4 +255,5 @@
tag: ".removed-api.txt",
},
],
+ api_surface: "system-server",
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 7f92960..cb58855 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -266,17 +266,17 @@
@Override
public void onUserUnlocking(@NonNull TargetUser user) {
- mStorageManagerService.onUnlockUser(user.getUserIdentifier());
+ mStorageManagerService.onUserUnlocking(user.getUserIdentifier());
}
@Override
public void onUserStopped(@NonNull TargetUser user) {
- mStorageManagerService.onCleanupUser(user.getUserIdentifier());
+ mStorageManagerService.onUserStopped(user.getUserIdentifier());
}
@Override
public void onUserStopping(@NonNull TargetUser user) {
- mStorageManagerService.onStopUser(user.getUserIdentifier());
+ mStorageManagerService.onUserStopping(user.getUserIdentifier());
}
@Override
@@ -1247,8 +1247,8 @@
}
}
- private void onUnlockUser(int userId) {
- Slog.d(TAG, "onUnlockUser " + userId);
+ private void onUserUnlocking(int userId) {
+ Slog.d(TAG, "onUserUnlocking " + userId);
if (userId != UserHandle.USER_SYSTEM) {
// Check if this user shares media with another user
@@ -1311,8 +1311,8 @@
}
}
- private void onCleanupUser(int userId) {
- Slog.d(TAG, "onCleanupUser " + userId);
+ private void onUserStopped(int userId) {
+ Slog.d(TAG, "onUserStopped " + userId);
try {
mVold.onUserStopped(userId);
@@ -1326,8 +1326,8 @@
}
}
- private void onStopUser(int userId) {
- Slog.i(TAG, "onStopUser " + userId);
+ private void onUserStopping(int userId) {
+ Slog.i(TAG, "onUserStopping " + userId);
try {
mStorageSessionController.onUserStopping(userId);
} catch (Exception e) {
diff --git a/services/core/java/com/android/server/connectivity/OWNERS b/services/core/java/com/android/server/connectivity/OWNERS
index 62c5737..c24680e9 100644
--- a/services/core/java/com/android/server/connectivity/OWNERS
+++ b/services/core/java/com/android/server/connectivity/OWNERS
@@ -1,2 +1,2 @@
set noparent
-file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
+file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking
diff --git a/services/core/java/com/android/server/net/OWNERS b/services/core/java/com/android/server/net/OWNERS
index 9c96d46f..d0e95dd 100644
--- a/services/core/java/com/android/server/net/OWNERS
+++ b/services/core/java/com/android/server/net/OWNERS
@@ -1,5 +1,5 @@
set noparent
-file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
+file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking
jsharkey@android.com
sudheersai@google.com
diff --git a/services/core/java/com/android/server/security/rkp/OWNERS b/services/core/java/com/android/server/security/rkp/OWNERS
index 348f940..ea6dc72 100644
--- a/services/core/java/com/android/server/security/rkp/OWNERS
+++ b/services/core/java/com/android/server/security/rkp/OWNERS
@@ -1 +1 @@
-file:platform/frameworks/base:master:/core/java/android/security/rkp/OWNERS
+file:platform/frameworks/base:main:/core/java/android/security/rkp/OWNERS
diff --git a/services/foldables/devicestateprovider/OWNERS b/services/foldables/devicestateprovider/OWNERS
new file mode 100644
index 0000000..5732844
--- /dev/null
+++ b/services/foldables/devicestateprovider/OWNERS
@@ -0,0 +1,6 @@
+akulian@google.com
+jiamingliu@google.com
+kchyn@google.com
+kennethford@google.com
+nickchameyev@google.com
+nicomazz@google.com
\ No newline at end of file
diff --git a/services/net/OWNERS b/services/net/OWNERS
index 62c5737..c24680e9 100644
--- a/services/net/OWNERS
+++ b/services/net/OWNERS
@@ -1,2 +1,2 @@
set noparent
-file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
+file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking
diff --git a/services/tests/RemoteProvisioningServiceTests/OWNERS b/services/tests/RemoteProvisioningServiceTests/OWNERS
index 348f940..ea6dc72 100644
--- a/services/tests/RemoteProvisioningServiceTests/OWNERS
+++ b/services/tests/RemoteProvisioningServiceTests/OWNERS
@@ -1 +1 @@
-file:platform/frameworks/base:master:/core/java/android/security/rkp/OWNERS
+file:platform/frameworks/base:main:/core/java/android/security/rkp/OWNERS
diff --git a/tests/BinderLeakTest/Android.bp b/tests/BinderLeakTest/Android.bp
new file mode 100644
index 0000000..78b0ede
--- /dev/null
+++ b/tests/BinderLeakTest/Android.bp
@@ -0,0 +1,40 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+ name: "binder_leak_test_aidl",
+ srcs: ["**/*.aidl"],
+ path: "aidl",
+}
+
+java_defaults {
+ name: "BinderTest.defaults",
+ srcs: [
+ "**/*.java",
+ ":binder_leak_test_aidl",
+ ],
+ static_libs: [
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ "androidx.test.runner",
+ ],
+}
+
+// Built with target_sdk_version: current
+android_test {
+ name: "BinderLeakTest",
+ defaults: ["BinderTest.defaults"],
+}
+
+// Built with target_sdk_version: 33
+android_test {
+ name: "BinderLeakTest_legacy",
+ defaults: ["BinderTest.defaults"],
+ manifest: "AndroidManifest_legacy.xml",
+}
diff --git a/tests/BinderLeakTest/AndroidManifest.xml b/tests/BinderLeakTest/AndroidManifest.xml
new file mode 100644
index 0000000..756def7
--- /dev/null
+++ b/tests/BinderLeakTest/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.binder">
+ <application>
+ <service
+ android:name=".MyService"
+ android:enabled="true"
+ android:exported="true"
+ android:process=":service">
+ </service>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.test.binder"
+ android:label="Binder leak test">
+ </instrumentation>
+</manifest>
diff --git a/tests/BinderLeakTest/AndroidManifest_legacy.xml b/tests/BinderLeakTest/AndroidManifest_legacy.xml
new file mode 100644
index 0000000..03d1dfd
--- /dev/null
+++ b/tests/BinderLeakTest/AndroidManifest_legacy.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.binder">
+ <uses-sdk android:minSdkVersion="33"
+ android:targetSdkVersion="33"
+ android:maxSdkVersion="33" />
+ <application>
+ <service
+ android:name=".MyService"
+ android:enabled="true"
+ android:exported="true"
+ android:process=":service">
+ </service>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.test.binder"
+ android:label="Binder leak test">
+ </instrumentation>
+</manifest>
diff --git a/tests/BinderLeakTest/aidl/com/android/test/binder/IFoo.aidl b/tests/BinderLeakTest/aidl/com/android/test/binder/IFoo.aidl
new file mode 100644
index 0000000..a721959
--- /dev/null
+++ b/tests/BinderLeakTest/aidl/com/android/test/binder/IFoo.aidl
@@ -0,0 +1,5 @@
+package com.android.test.binder;
+
+interface IFoo {
+
+}
diff --git a/tests/BinderLeakTest/aidl/com/android/test/binder/IFooProvider.aidl b/tests/BinderLeakTest/aidl/com/android/test/binder/IFooProvider.aidl
new file mode 100644
index 0000000..b487f51
--- /dev/null
+++ b/tests/BinderLeakTest/aidl/com/android/test/binder/IFooProvider.aidl
@@ -0,0 +1,10 @@
+package com.android.test.binder;
+import com.android.test.binder.IFoo;
+
+interface IFooProvider {
+ IFoo createFoo();
+
+ boolean isFooGarbageCollected();
+
+ oneway void killProcess();
+}
diff --git a/tests/BinderLeakTest/java/com/android/test/binder/BinderTest.java b/tests/BinderLeakTest/java/com/android/test/binder/BinderTest.java
new file mode 100644
index 0000000..f07317f
--- /dev/null
+++ b/tests/BinderLeakTest/java/com/android/test/binder/BinderTest.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2023 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.test.binder;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Intent;
+import android.os.Build;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.rule.ServiceTestRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(AndroidJUnit4.class)
+public class BinderTest {
+ @Rule
+ public final ServiceTestRule serviceRule = new ServiceTestRule();
+
+ @Test
+ public void testDeathRecipientLeaksOrNot()
+ throws RemoteException, TimeoutException, InterruptedException {
+ Intent intent = new Intent(ApplicationProvider.getApplicationContext(), MyService.class);
+ IFooProvider provider = IFooProvider.Stub.asInterface(serviceRule.bindService(intent));
+ FooHolder holder = new FooHolder(provider.createFoo());
+
+ // ref will get enqueued right after holder is finalized for gc.
+ ReferenceQueue<FooHolder> refQueue = new ReferenceQueue<>();
+ PhantomReference<FooHolder> ref = new PhantomReference<>(holder, refQueue);
+
+ DeathRecorder deathRecorder = new DeathRecorder();
+ holder.registerDeathRecorder(deathRecorder);
+
+ if (getSdkVersion() >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+ /////////////////////////////////////////////
+ // New behavior
+ //
+ // Reference chain at this moment:
+ // holder --(java strong ref)--> FooHolder
+ // FooHolder.mProxy --(java strong ref)--> IFoo.Proxy
+ // IFoo.Proxy.mRemote --(java strong ref)--> BinderProxy
+ // BinderProxy --(binder ref)--> Foo.Stub
+ // In other words, the variable "holder" is the root of the reference chain.
+
+ // By setting the variable to null, we make FooHolder, IFoo.Proxy, BinderProxy, and even
+ // Foo.Stub unreachable.
+ holder = null;
+
+ // Ensure that the objects are garbage collected
+ forceGc();
+ assertEquals(ref, refQueue.poll());
+ assertTrue(provider.isFooGarbageCollected());
+
+ // The binder has died, but we don't get notified since the death recipient is GC'ed.
+ provider.killProcess();
+ Thread.sleep(1000); // give some time for the service process to die and reaped
+ assertFalse(deathRecorder.deathRecorded);
+ } else {
+ /////////////////////////////////////////////
+ // Legacy behavior
+ //
+ // Reference chain at this moment:
+ // JavaDeathRecipient --(JNI strong ref)--> FooHolder
+ // holder --(java strong ref)--> FooHolder
+ // FooHolder.mProxy --(java strong ref)--> IFoo.Proxy
+ // IFoo.Proxy.mRemote --(java strong ref)--> BinderProxy
+ // BinderProxy --(binder ref)--> Foo.Stub
+ // So, BOTH JavaDeathRecipient and holder are roots of the reference chain.
+
+ // Even if we set holder to null, it doesn't make other objects unreachable; they are
+ // still reachable via the JNI strong ref.
+ holder = null;
+
+ // Check that objects are not garbage collected
+ forceGc();
+ assertNotEquals(ref, refQueue.poll());
+ assertFalse(provider.isFooGarbageCollected());
+
+ // The legacy behavior is getting notified even when there's no reference
+ provider.killProcess();
+ Thread.sleep(1000); // give some time for the service process to die and reaped
+ assertTrue(deathRecorder.deathRecorded);
+ }
+ }
+
+ static class FooHolder implements IBinder.DeathRecipient {
+ private IFoo mProxy;
+ private DeathRecorder mDeathRecorder;
+
+ FooHolder(IFoo proxy) throws RemoteException {
+ proxy.asBinder().linkToDeath(this, 0);
+
+ // A strong reference from DeathRecipient(this) to the binder proxy is created here
+ mProxy = proxy;
+ }
+
+ public void registerDeathRecorder(DeathRecorder dr) {
+ mDeathRecorder = dr;
+ }
+
+ @Override
+ public void binderDied() {
+ if (mDeathRecorder != null) {
+ mDeathRecorder.deathRecorded = true;
+ }
+ }
+ }
+
+ static class DeathRecorder {
+ public boolean deathRecorded = false;
+ }
+
+ // Try calling System.gc() until an orphaned object is confirmed to be finalized
+ private static void forceGc() {
+ Object obj = new Object();
+ ReferenceQueue<Object> refQueue = new ReferenceQueue<>();
+ PhantomReference<Object> ref = new PhantomReference<>(obj, refQueue);
+ obj = null; // make it an orphan
+ while (refQueue.poll() != ref) {
+ System.gc();
+ }
+ }
+
+ private static int getSdkVersion() {
+ return ApplicationProvider.getApplicationContext().getApplicationInfo().targetSdkVersion;
+ }
+}
diff --git a/tests/BinderLeakTest/java/com/android/test/binder/MyService.java b/tests/BinderLeakTest/java/com/android/test/binder/MyService.java
new file mode 100644
index 0000000..c701253
--- /dev/null
+++ b/tests/BinderLeakTest/java/com/android/test/binder/MyService.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 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.test.binder;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+
+public class MyService extends Service {
+ @Override
+ public IBinder onBind(Intent intent) {
+ return new IFooProvider.Stub() {
+ ReferenceQueue<IFoo> mRefQueue = new ReferenceQueue<>();
+ PhantomReference<IFoo> mRef;
+
+ @Override
+ public IFoo createFoo() throws RemoteException {
+ IFoo binder = new IFoo.Stub() {};
+ mRef = new PhantomReference<>(binder, mRefQueue);
+ return binder;
+ }
+
+ @Override
+ public boolean isFooGarbageCollected() throws RemoteException {
+ forceGc();
+ return mRefQueue.poll() == mRef;
+ }
+
+ @Override
+ public void killProcess() throws RemoteException {
+ android.os.Process.killProcess(android.os.Process.myPid());
+ }
+ };
+ }
+
+ private static void forceGc() {
+ Object obj = new Object();
+ ReferenceQueue<Object> refQueue = new ReferenceQueue<>();
+ PhantomReference<Object> ref = new PhantomReference<>(obj, refQueue);
+ obj = null; // make it an orphan
+ while (refQueue.poll() != ref) {
+ System.gc();
+ }
+ }
+}
diff --git a/tests/NetworkSecurityConfigTest/res/raw/ca_certs_der.der b/tests/NetworkSecurityConfigTest/res/raw/ca_certs_der.der
index 235bd47..fd888ec 100644
--- a/tests/NetworkSecurityConfigTest/res/raw/ca_certs_der.der
+++ b/tests/NetworkSecurityConfigTest/res/raw/ca_certs_der.der
Binary files differ
diff --git a/tests/NetworkSecurityConfigTest/res/raw/ca_certs_pem.pem b/tests/NetworkSecurityConfigTest/res/raw/ca_certs_pem.pem
index 413e3c0..66f7bfd 100644
--- a/tests/NetworkSecurityConfigTest/res/raw/ca_certs_pem.pem
+++ b/tests/NetworkSecurityConfigTest/res/raw/ca_certs_pem.pem
@@ -1,35 +1,31 @@
-----BEGIN CERTIFICATE-----
-MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
-MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
-aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw
-WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE
-AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m
-OSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu
-T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c
-JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR
-Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz
-PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm
-aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM
-TjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA6BgNVHR8EMzAxMC+g
-LaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL3NlY3VyZWNhLmNybDBO
-BgNVHSAERzBFMEMGBFUdIAAwOzA5BggrBgEFBQcCARYtaHR0cHM6Ly93d3cuZ2Vv
-dHJ1c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5MA0GCSqGSIb3DQEBBQUAA4GB
-AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL
-NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W
-b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG
-A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
-cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
-MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
-BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
-YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
-ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
-BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
-I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
-CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i
-2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ
-2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ
+MIIFYjCCBEqgAwIBAgIQd70NbNs2+RrqIQ/E8FjTDTANBgkqhkiG9w0BAQsFADBX
+MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UE
+CxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTIwMDYx
+OTAwMDA0MloXDTI4MDEyODAwMDA0MlowRzELMAkGA1UEBhMCVVMxIjAgBgNVBAoT
+GUdvb2dsZSBUcnVzdCBTZXJ2aWNlcyBMTEMxFDASBgNVBAMTC0dUUyBSb290IFIx
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAthECix7joXebO9y/lD63
+ladAPKH9gvl9MgaCcfb2jH/76Nu8ai6Xl6OMS/kr9rH5zoQdsfnFl97vufKj6bwS
+iV6nqlKr+CMny6SxnGPb15l+8Ape62im9MZaRw1NEDPjTrETo8gYbEvs/AmQ351k
+KSUjB6G00j0uYODP0gmHu81I8E3CwnqIiru6z1kZ1q+PsAewnjHxgsHA3y6mbWwZ
+DrXYfiYaRQM9sHmklCitD38m5agI/pboPGiUU+6DOogrFZYJsuB6jC511pzrp1Zk
+j5ZPaK49l8KEj8C8QMALXL32h7M1bKwYUH+E4EzNktMg6TO8UpmvMrUpsyUqtEj5
+cuHKZPfmghCN6J3Cioj6OGaK/GP5Afl4/Xtcd/p2h/rs37EOeZVXtL0m79YB0esW
+CruOC7XFxYpVq9Os6pFLKcwZpDIlTirxZUTQAs6qzkm06p98g7BAe+dDq6dso499
+iYH6TKX/1Y7DzkvgtdizjkXPdsDtQCv9Uw+wp9U7DbGKogPeMa3Md+pvez7W35Ei
+Eua++tgy/BBjFFFy3l3WFpO9KWgz7zpm7AeKJt8T11dleCfeXkkUAKIAf5qoIbap
+sZWwpbkNFhHax2xIPEDgfg1azVY80ZcFuctL7TlLnMQ/0lUTbiSw1nH69MG6zO0b
+9f6BQdgAmD06yK56mDcYBZUCAwEAAaOCATgwggE0MA4GA1UdDwEB/wQEAwIBhjAP
+BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTkrysmcRorSCeFL1JmLO/wiRNxPjAf
+BgNVHSMEGDAWgBRge2YaRQ2XyolQL30EzTSo//z9SzBgBggrBgEFBQcBAQRUMFIw
+JQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnBraS5nb29nL2dzcjEwKQYIKwYBBQUH
+MAKGHWh0dHA6Ly9wa2kuZ29vZy9nc3IxL2dzcjEuY3J0MDIGA1UdHwQrMCkwJ6Al
+oCOGIWh0dHA6Ly9jcmwucGtpLmdvb2cvZ3NyMS9nc3IxLmNybDA7BgNVHSAENDAy
+MAgGBmeBDAECATAIBgZngQwBAgIwDQYLKwYBBAHWeQIFAwIwDQYLKwYBBAHWeQIF
+AwMwDQYJKoZIhvcNAQELBQADggEBADSkHrEoo9C0dhemMXoh6dFSPsjbdBZBiLg9
+NR3t5P+T4Vxfq7vqfM/b5A3Ri1fyJm9bvhdGaJQ3b2t6yMAYN/olUazsaL+yyEn9
+WprKASOshIArAoyZl+tJaox118fessmXn1hIVw41oeQa1v1vg4Fv74zPl6/AhSrw
+9U5pCZEt4Wi4wStz6dTZ/CLANx8LZh1J7QJVj2fhMtfTJr9w4z30Z209fOU0iOMy
++qduBmpvvYuR7hZL6Dupszfnw0Skfths18dG9ZKb59UhvmaSGZRVbNQpsg3BZlvi
+d0lIKO2d1xozclOzgjXPYovJJIultzkMu34qQb9Sz/yilrbCgj8=
-----END CERTIFICATE-----
diff --git a/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml b/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml
index 5d23d36e..99106ad 100644
--- a/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml
+++ b/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml
@@ -5,7 +5,7 @@
</domain>
<domain> developer.android.com </domain>
<pin-set>
- <pin digest="SHA-256"> 7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y= </pin>
+ <pin digest="SHA-256"> zCTnfLwLKbS9S2sbp+uFz4KZOocFvXxkV06Ce9O5M2w= </pin>
</pin-set>
</domain-config>
</network-security-config>
diff --git a/tests/NetworkSecurityConfigTest/res/xml/nested_domains.xml b/tests/NetworkSecurityConfigTest/res/xml/nested_domains.xml
index d45fd77..232f88f 100644
--- a/tests/NetworkSecurityConfigTest/res/xml/nested_domains.xml
+++ b/tests/NetworkSecurityConfigTest/res/xml/nested_domains.xml
@@ -9,7 +9,7 @@
<domain-config>
<domain>developer.android.com</domain>
<pin-set>
- <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
+ <pin digest="SHA-256">zCTnfLwLKbS9S2sbp+uFz4KZOocFvXxkV06Ce9O5M2w=</pin>
</pin-set>
</domain-config>
</domain-config>
diff --git a/tests/NetworkSecurityConfigTest/res/xml/pins1.xml b/tests/NetworkSecurityConfigTest/res/xml/pins1.xml
index 1773d280..7cc81b0 100644
--- a/tests/NetworkSecurityConfigTest/res/xml/pins1.xml
+++ b/tests/NetworkSecurityConfigTest/res/xml/pins1.xml
@@ -3,7 +3,7 @@
<domain-config>
<domain>android.com</domain>
<pin-set>
- <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
+ <pin digest="SHA-256">zCTnfLwLKbS9S2sbp+uFz4KZOocFvXxkV06Ce9O5M2w=</pin>
</pin-set>
</domain-config>
</network-security-config>
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
index 047be16..0494f17 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
@@ -22,23 +22,17 @@
import android.test.ActivityUnitTestCase;
import android.util.ArraySet;
import android.util.Pair;
+
+import com.android.org.conscrypt.TrustedCertificateStore;
+
import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.net.Socket;
-import java.net.URL;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.TrustManager;
-import com.android.org.conscrypt.TrustedCertificateStore;
+import javax.net.ssl.SSLContext;
public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> {
@@ -46,9 +40,9 @@
super(Activity.class);
}
- // SHA-256 of the G2 intermediate CA for android.com (as of 10/2015).
- private static final byte[] G2_SPKI_SHA256
- = hexToBytes("ec722969cb64200ab6638f68ac538e40abab5b19a6485661042a1061c4612776");
+ // SHA-256 of the GTS intermediate CA (CN = GTS CA 1C3) for android.com (as of 09/2023).
+ private static final byte[] GTS_INTERMEDIATE_SPKI_SHA256 =
+ hexToBytes("cc24e77cbc0b29b4bd4b6b1ba7eb85cf82993a8705bd7c64574e827bd3b9336c");
private static final byte[] TEST_CA_BYTES
= hexToBytes(
@@ -161,7 +155,7 @@
public void testGoodPin() throws Exception {
ArraySet<Pin> pins = new ArraySet<Pin>();
- pins.add(new Pin("SHA-256", G2_SPKI_SHA256));
+ pins.add(new Pin("SHA-256", GTS_INTERMEDIATE_SPKI_SHA256));
NetworkSecurityConfig domain = new NetworkSecurityConfig.Builder()
.setPinSet(new PinSet(pins, Long.MAX_VALUE))
.addCertificatesEntryRef(
@@ -247,7 +241,7 @@
public void testWithUrlConnection() throws Exception {
ArraySet<Pin> pins = new ArraySet<Pin>();
- pins.add(new Pin("SHA-256", G2_SPKI_SHA256));
+ pins.add(new Pin("SHA-256", GTS_INTERMEDIATE_SPKI_SHA256));
NetworkSecurityConfig domain = new NetworkSecurityConfig.Builder()
.setPinSet(new PinSet(pins, Long.MAX_VALUE))
.addCertificatesEntryRef(
@@ -304,7 +298,7 @@
} finally {
// Delete the user added CA. We don't know the alias so just delete them all.
for (String alias : store.aliases()) {
- if (store.isUser(alias)) {
+ if (TrustedCertificateStore.isUser(alias)) {
try {
store.deleteCertificateEntry(alias);
} catch (Exception ignored) {
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java
index 9dec21b..39b5cb4c 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java
@@ -16,19 +16,20 @@
package android.security.net.config;
+import static org.junit.Assert.fail;
+
import android.content.pm.ApplicationInfo;
import android.os.Build;
-import java.net.Socket;
+
import java.net.URL;
+
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.TrustManager;
+import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManagerFactory;
-import junit.framework.Assert;
-
-public final class TestUtils extends Assert {
+public final class TestUtils {
private TestUtils() {
}
@@ -36,8 +37,8 @@
public static void assertConnectionFails(SSLContext context, String host, int port)
throws Exception {
try {
- Socket s = context.getSocketFactory().createSocket(host, port);
- s.getInputStream();
+ SSLSocket s = (SSLSocket) context.getSocketFactory().createSocket(host, port);
+ s.startHandshake();
fail("Expected connection to " + host + ":" + port + " to fail.");
} catch (SSLHandshakeException expected) {
}
@@ -45,7 +46,8 @@
public static void assertConnectionSucceeds(SSLContext context, String host, int port)
throws Exception {
- Socket s = context.getSocketFactory().createSocket(host, port);
+ SSLSocket s = (SSLSocket) context.getSocketFactory().createSocket(host, port);
+ s.startHandshake();
s.getInputStream();
}
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
index 4b7a014..81e05c1 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
@@ -16,26 +16,18 @@
package android.security.net.config;
-import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.test.AndroidTestCase;
import android.test.MoreAsserts;
-import android.util.ArraySet;
-import android.util.Pair;
+
import java.io.IOException;
import java.net.InetAddress;
-import java.net.Socket;
-import java.net.URL;
import java.security.KeyStore;
import java.security.Provider;
-import java.security.Security;
import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.Set;
-import javax.net.ssl.HttpsURLConnection;
+
import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
@@ -52,7 +44,7 @@
NetworkSecurityConfig config = appConfig.getConfigForHostname("");
assertNotNull(config);
// Check defaults.
- assertTrue(config.isCleartextTrafficPermitted());
+ assertFalse(config.isCleartextTrafficPermitted());
assertFalse(config.isHstsEnforced());
assertFalse(config.getTrustAnchors().isEmpty());
PinSet pinSet = config.getPins();
@@ -72,7 +64,7 @@
NetworkSecurityConfig config = appConfig.getConfigForHostname("");
assertNotNull(config);
// Check defaults.
- assertTrue(config.isCleartextTrafficPermitted());
+ assertFalse(config.isCleartextTrafficPermitted());
assertFalse(config.isHstsEnforced());
assertTrue(config.getTrustAnchors().isEmpty());
PinSet pinSet = config.getPins();
@@ -91,14 +83,14 @@
NetworkSecurityConfig config = appConfig.getConfigForHostname("");
assertNotNull(config);
// Check defaults.
- assertTrue(config.isCleartextTrafficPermitted());
+ assertFalse(config.isCleartextTrafficPermitted());
assertFalse(config.isHstsEnforced());
assertTrue(config.getTrustAnchors().isEmpty());
PinSet pinSet = config.getPins();
assertTrue(pinSet.pins.isEmpty());
// Check android.com.
config = appConfig.getConfigForHostname("android.com");
- assertTrue(config.isCleartextTrafficPermitted());
+ assertFalse(config.isCleartextTrafficPermitted());
assertFalse(config.isHstsEnforced());
assertFalse(config.getTrustAnchors().isEmpty());
pinSet = config.getPins();
@@ -188,7 +180,7 @@
ApplicationConfig appConfig = new ApplicationConfig(source);
assertTrue(appConfig.hasPerDomainConfigs());
NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
- assertTrue(config.isCleartextTrafficPermitted());
+ assertFalse(config.isCleartextTrafficPermitted());
assertFalse(config.isHstsEnforced());
assertFalse(config.getTrustAnchors().isEmpty());
PinSet pinSet = config.getPins();
@@ -250,9 +242,9 @@
ApplicationConfig appConfig = new ApplicationConfig(source);
// Check android.com.
NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
- assertTrue(config.isCleartextTrafficPermitted());
+ assertFalse(config.isCleartextTrafficPermitted());
assertFalse(config.isHstsEnforced());
- assertEquals(2, config.getTrustAnchors().size());
+ assertEquals(1, config.getTrustAnchors().size());
// Try connections.
SSLContext context = TestUtils.getSSLContext(source);
TestUtils.assertConnectionSucceeds(context, "android.com", 443);
@@ -267,9 +259,9 @@
ApplicationConfig appConfig = new ApplicationConfig(source);
// Check android.com.
NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com");
- assertTrue(config.isCleartextTrafficPermitted());
+ assertFalse(config.isCleartextTrafficPermitted());
assertFalse(config.isHstsEnforced());
- assertEquals(2, config.getTrustAnchors().size());
+ assertEquals(1, config.getTrustAnchors().size());
// Try connections.
SSLContext context = TestUtils.getSSLContext(source);
TestUtils.assertConnectionSucceeds(context, "android.com", 443);
diff --git a/tools/lint/fix/soong_lint_fix.py b/tools/lint/fix/soong_lint_fix.py
index 4a2e37e..2e82beb 100644
--- a/tools/lint/fix/soong_lint_fix.py
+++ b/tools/lint/fix/soong_lint_fix.py
@@ -14,6 +14,7 @@
import argparse
import json
+import functools
import os
import shutil
import subprocess
@@ -28,6 +29,7 @@
PATH_PREFIX = "out/soong/.intermediates"
PATH_SUFFIX = "android_common/lint"
FIX_ZIP = "suggested-fixes.zip"
+MODULE_JAVA_DEPS = "out/soong/module_bp_java_deps.json"
class SoongModule:
@@ -49,11 +51,26 @@
print(f"Found module {partial_path}/{self._name}.")
self._path = f"{PATH_PREFIX}/{partial_path}/{self._name}/{PATH_SUFFIX}"
+ def find_java_deps(self, module_java_deps):
+ """Finds the dependencies of a Java module in the loaded module_bp_java_deps.json.
+
+ Returns:
+ A list of module names.
+ """
+ if self._name not in module_java_deps:
+ raise Exception(f"Module {self._name} not found!")
+
+ return module_java_deps[self._name]["dependencies"]
+
@property
def name(self):
return self._name
@property
+ def path(self):
+ return self._path
+
+ @property
def lint_report(self):
return f"{self._path}/lint-report.txt"
@@ -62,52 +79,25 @@
return f"{self._path}/{FIX_ZIP}"
-class SoongLintFix:
+class SoongLintWrapper:
"""
- This class creates a command line tool that will apply lint fixes to the
- platform via the necessary combination of soong and shell commands.
+ This class wraps the necessary calls to Soong and/or shell commands to lint
+ platform modules and apply suggested fixes if desired.
- It breaks up these operations into a few "private" methods that are
- intentionally exposed so experimental code can tweak behavior.
-
- The entry point, `run`, will apply lint fixes using the intermediate
- `suggested-fixes` directory that soong creates during its invocation of
- lint.
-
- Basic usage:
- ```
- from soong_lint_fix import SoongLintFix
-
- opts = SoongLintFixOptions()
- opts.parse_args(sys.argv)
- SoongLintFix(opts).run()
- ```
+ It breaks up these operations into a few methods that are available to
+ sub-classes (see SoongLintFix for an example).
"""
- def __init__(self, opts):
- self._opts = opts
+ def __init__(self, check=None, lint_module=None):
+ self._check = check
+ self._lint_module = lint_module
self._kwargs = None
- self._modules = []
-
- def run(self):
- """
- Run the script
- """
- self._setup()
- self._find_modules()
- self._lint()
-
- if not self._opts.no_fix:
- self._fix()
-
- if self._opts.print:
- self._print()
def _setup(self):
env = os.environ.copy()
- if self._opts.check:
- env["ANDROID_LINT_CHECK"] = self._opts.check
- if self._opts.lint_module:
- env["ANDROID_LINT_CHECK_EXTRA_MODULES"] = self._opts.lint_module
+ if self._check:
+ env["ANDROID_LINT_CHECK"] = self._check
+ if self._lint_module:
+ env["ANDROID_LINT_CHECK_EXTRA_MODULES"] = self._lint_module
self._kwargs = {
"env": env,
@@ -117,7 +107,10 @@
os.chdir(ANDROID_BUILD_TOP)
- print("Refreshing soong modules...")
+ @functools.cached_property
+ def _module_info(self):
+ """Returns the JSON content of module-info.json."""
+ print("Refreshing Soong modules...")
try:
os.mkdir(ANDROID_PRODUCT_OUT)
except OSError:
@@ -125,19 +118,54 @@
subprocess.call(f"{SOONG_UI} --make-mode {PRODUCT_OUT}/module-info.json", **self._kwargs)
print("done.")
-
- def _find_modules(self):
with open(f"{ANDROID_PRODUCT_OUT}/module-info.json") as f:
- module_info = json.load(f)
+ return json.load(f)
- for module_name in self._opts.modules:
- module = SoongModule(module_name)
- module.find(module_info)
- self._modules.append(module)
+ def _find_module(self, module_name):
+ """Returns a SoongModule from a module name.
- def _lint(self):
+ Ensures that the module is known to Soong.
+ """
+ module = SoongModule(module_name)
+ module.find(self._module_info)
+ return module
+
+ def _find_modules(self, module_names):
+ modules = []
+ for module_name in module_names:
+ modules.append(self._find_module(module_name))
+ return modules
+
+ @functools.cached_property
+ def _module_java_deps(self):
+ """Returns the JSON content of module_bp_java_deps.json."""
+ print("Refreshing Soong Java deps...")
+ subprocess.call(f"{SOONG_UI} --make-mode {MODULE_JAVA_DEPS}", **self._kwargs)
+ print("done.")
+
+ with open(f"{MODULE_JAVA_DEPS}") as f:
+ return json.load(f)
+
+ def _find_module_java_deps(self, module):
+ """Returns a list a dependencies for a module.
+
+ Args:
+ module: A SoongModule.
+
+ Returns:
+ A list of SoongModule.
+ """
+ deps = []
+ dep_names = module.find_java_deps(self._module_java_deps)
+ for dep_name in dep_names:
+ dep = SoongModule(dep_name)
+ dep.find(self._module_info)
+ deps.append(dep)
+ return deps
+
+ def _lint(self, modules):
print("Cleaning up any old lint results...")
- for module in self._modules:
+ for module in modules:
try:
os.remove(f"{module.lint_report}")
os.remove(f"{module.suggested_fixes}")
@@ -145,13 +173,13 @@
pass
print("done.")
- target = " ".join([ module.lint_report for module in self._modules ])
+ target = " ".join([ module.lint_report for module in modules ])
print(f"Generating {target}")
subprocess.call(f"{SOONG_UI} --make-mode {target}", **self._kwargs)
print("done.")
- def _fix(self):
- for module in self._modules:
+ def _fix(self, modules):
+ for module in modules:
print(f"Copying suggested fixes for {module.name} to the tree...")
with zipfile.ZipFile(f"{module.suggested_fixes}") as zip:
for name in zip.namelist():
@@ -161,13 +189,40 @@
shutil.copyfileobj(src, dst)
print("done.")
- def _print(self):
- for module in self._modules:
+ def _print(self, modules):
+ for module in modules:
print(f"### lint-report.txt {module.name} ###", end="\n\n")
with open(module.lint_report, "r") as f:
print(f.read())
+class SoongLintFix(SoongLintWrapper):
+ """
+ Basic usage:
+ ```
+ from soong_lint_fix import SoongLintFix
+
+ opts = SoongLintFixOptions()
+ opts.parse_args()
+ SoongLintFix(opts).run()
+ ```
+ """
+ def __init__(self, opts):
+ super().__init__(check=opts.check, lint_module=opts.lint_module)
+ self._opts = opts
+
+ def run(self):
+ self._setup()
+ modules = self._find_modules(self._opts.modules)
+ self._lint(modules)
+
+ if not self._opts.no_fix:
+ self._fix(modules)
+
+ if self._opts.print:
+ self._print(modules)
+
+
class SoongLintFixOptions:
"""Options for SoongLintFix"""
diff --git a/tools/lint/utils/enforce_permission_counter.py b/tools/lint/utils/enforce_permission_counter.py
index b5c2ffe..a4c00f7 100644
--- a/tools/lint/utils/enforce_permission_counter.py
+++ b/tools/lint/utils/enforce_permission_counter.py
@@ -16,57 +16,38 @@
import soong_lint_fix
-# Libraries that constitute system_server.
-# It is non-trivial to keep in sync with services/Android.bp as some
-# module are post-processed (e.g, services.core).
-TARGETS = [
- "services.core.unboosted",
- "services.accessibility",
- "services.appprediction",
- "services.appwidget",
- "services.autofill",
- "services.backup",
- "services.companion",
- "services.contentcapture",
- "services.contentsuggestions",
- "services.coverage",
- "services.devicepolicy",
- "services.midi",
- "services.musicsearch",
- "services.net",
- "services.people",
- "services.print",
- "services.profcollect",
- "services.restrictions",
- "services.searchui",
- "services.smartspace",
- "services.systemcaptions",
- "services.translation",
- "services.texttospeech",
- "services.usage",
- "services.usb",
- "services.voiceinteraction",
- "services.wallpapereffectsgeneration",
- "services.wifi",
-]
+CHECK = "AnnotatedAidlCounter"
+LINT_MODULE = "AndroidUtilsLintChecker"
-
-class EnforcePermissionMigratedCounter:
+class EnforcePermissionMigratedCounter(soong_lint_fix.SoongLintWrapper):
"""Wrapper around lint_fix to count the number of AIDL methods annotated."""
+
+ def __init__(self):
+ super().__init__(check=CHECK, lint_module=LINT_MODULE)
+
def run(self):
- opts = soong_lint_fix.SoongLintFixOptions()
- opts.check = "AnnotatedAidlCounter"
- opts.lint_module = "AndroidUtilsLintChecker"
- opts.no_fix = True
- opts.modules = TARGETS
+ self._setup()
- self.linter = soong_lint_fix.SoongLintFix(opts)
- self.linter.run()
- self.parse_lint_reports()
+ # Analyze the dependencies of the "services" module and the module
+ # "services.core.unboosted".
+ service_module = self._find_module("services")
+ dep_modules = self._find_module_java_deps(service_module) + \
+ [self._find_module("services.core.unboosted")]
- def parse_lint_reports(self):
+ # Skip dependencies that are not services. Skip the "services.core"
+ # module which is analyzed via "services.core.unboosted".
+ modules = []
+ for module in dep_modules:
+ if "frameworks/base/services" not in module.path:
+ continue
+ if module.name == "services.core":
+ continue
+ modules.append(module)
+
+ self._lint(modules)
+
counts = { "unannotated": 0, "enforced": 0, "notRequired": 0 }
- for module in self.linter._modules:
+ for module in modules:
with open(module.lint_report, "r") as f:
content = f.read()
keys = dict(re.findall(r'(\w+)=(\d+)', content))