diff options
Diffstat (limited to 'tools')
238 files changed, 9402 insertions, 289 deletions
diff --git a/tools/aapt/SdkConstants.h b/tools/aapt/SdkConstants.h index e2c161482857..ebb82ce1e2b7 100644 --- a/tools/aapt/SdkConstants.h +++ b/tools/aapt/SdkConstants.h @@ -50,6 +50,7 @@ enum { SDK_S_V2 = 32, SDK_TIRAMISU = 33, SDK_UPSIDE_DOWN_CAKE = 34, + SDK_VANILLA_ICE_CREAM = 35, SDK_CUR_DEVELOPMENT = 10000, }; diff --git a/tools/aapt2/SdkConstants.h b/tools/aapt2/SdkConstants.h index e47704ea2725..f131cc6d7553 100644 --- a/tools/aapt2/SdkConstants.h +++ b/tools/aapt2/SdkConstants.h @@ -60,6 +60,7 @@ enum : ApiVersion { SDK_S_V2 = 32, SDK_TIRAMISU = 33, SDK_UPSIDE_DOWN_CAKE = 34, + SDK_VANILLA_ICE_CREAM = 35, SDK_CUR_DEVELOPMENT = 10000, }; diff --git a/tools/aapt2/optimize/VersionCollapser.cpp b/tools/aapt2/optimize/VersionCollapser.cpp index cd791bda250b..27fff9a05334 100644 --- a/tools/aapt2/optimize/VersionCollapser.cpp +++ b/tools/aapt2/optimize/VersionCollapser.cpp @@ -70,7 +70,7 @@ FilterIterator<Iterator, Pred> make_filter_iterator(Iterator begin, * exception is when there is no exact matching resource for the minSdk. The next smallest one will * be kept. */ -static void CollapseVersions(int min_sdk, ResourceEntry* entry) { +static void CollapseVersions(IAaptContext* context, int min_sdk, ResourceEntry* entry) { // First look for all sdks less than minSdk. for (auto iter = entry->values.rbegin(); iter != entry->values.rend(); ++iter) { @@ -102,7 +102,14 @@ static void CollapseVersions(int min_sdk, ResourceEntry* entry) { auto filter_iter = make_filter_iterator(iter + 1, entry->values.rend(), pred); while (filter_iter.HasNext()) { - filter_iter.Next() = {}; + auto& next = filter_iter.Next(); + if (context->IsVerbose()) { + context->GetDiagnostics()->Note(android::DiagMessage() + << "removing configuration " << next->config.to_string() + << " for entry: " << entry->name + << ", because its SDK version is smaller than minSdk"); + } + next = {}; } } } @@ -126,6 +133,12 @@ static void CollapseVersions(int min_sdk, ResourceEntry* entry) { util::make_unique<ResourceConfigValue>( config_value->config.CopyWithoutSdkVersion(), config_value->product); + if (context->IsVerbose()) { + context->GetDiagnostics()->Note(android::DiagMessage() + << "overriding resource: " << entry->name + << ", removing SDK version from configuration " + << config_value->config.to_string()); + } new_value->value = std::move(config_value->value); config_value = std::move(new_value); @@ -147,10 +160,14 @@ static void CollapseVersions(int min_sdk, ResourceEntry* entry) { bool VersionCollapser::Consume(IAaptContext* context, ResourceTable* table) { TRACE_NAME("VersionCollapser::Consume"); const int min_sdk = context->GetMinSdkVersion(); + if (context->IsVerbose()) { + context->GetDiagnostics()->Note(android::DiagMessage() + << "Running VersionCollapser with minSdk = " << min_sdk); + } for (auto& package : table->packages) { for (auto& type : package->types) { for (auto& entry : type->entries) { - CollapseVersions(min_sdk, entry.get()); + CollapseVersions(context, min_sdk, entry.get()); } } } diff --git a/tools/app_metadata_bundles/Android.bp b/tools/app_metadata_bundles/Android.bp new file mode 100644 index 000000000000..dced50d7ee3b --- /dev/null +++ b/tools/app_metadata_bundles/Android.bp @@ -0,0 +1,42 @@ +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"], + default_team: "trendy_team_preload_safety", +} + +java_library_host { + name: "asllib", + srcs: [ + "src/lib/java/**/*.java", + ], + static_libs: [ + "guava", + ], +} + +java_binary_host { + name: "aslgen", + manifest: "src/aslgen/aslgen.mf", + srcs: [ + "src/aslgen/java/**/*.java", + ], + static_libs: [ + "asllib", + ], +} + +java_test_host { + name: "aslgen-test", + srcs: ["src/test/java/**/*.java"], + exclude_srcs: [ + ], + java_resource_dirs: ["src/test/resources"], + static_libs: [ + "aslgen", + "junit", + ], +} diff --git a/tools/app_metadata_bundles/OWNERS b/tools/app_metadata_bundles/OWNERS new file mode 100644 index 000000000000..a2a250b2d5b7 --- /dev/null +++ b/tools/app_metadata_bundles/OWNERS @@ -0,0 +1,2 @@ +wenhaowang@google.com +mloh@google.com diff --git a/tools/app_metadata_bundles/README.md b/tools/app_metadata_bundles/README.md new file mode 100644 index 000000000000..6e8d287b41dd --- /dev/null +++ b/tools/app_metadata_bundles/README.md @@ -0,0 +1,9 @@ +# App metadata bundles + +This project delivers a comprehensive toolchain solution for developers +to efficiently manage app metadata bundles. + +The project consists of two subprojects: + + * A pure Java library, and + * A pure Java command-line tool. diff --git a/tools/app_metadata_bundles/src/aslgen/aslgen.mf b/tools/app_metadata_bundles/src/aslgen/aslgen.mf new file mode 100644 index 000000000000..fc656e2155a7 --- /dev/null +++ b/tools/app_metadata_bundles/src/aslgen/aslgen.mf @@ -0,0 +1 @@ +Main-Class: com.android.aslgen.Main
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/aslgen/java/com/android/aslgen/Main.java b/tools/app_metadata_bundles/src/aslgen/java/com/android/aslgen/Main.java new file mode 100644 index 000000000000..d7edfd44019c --- /dev/null +++ b/tools/app_metadata_bundles/src/aslgen/java/com/android/aslgen/Main.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2024 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.aslgen; + +import com.android.asllib.AslConverter; +import com.android.asllib.AslConverter.Format; +import com.android.asllib.util.MalformedXmlException; + +import org.xml.sax.SAXException; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; + +public class Main { + + /** Takes the options to make file conversion. */ + public static void main(String[] args) + throws IOException, + ParserConfigurationException, + SAXException, + TransformerException, + MalformedXmlException { + + String inFile = null; + String outFile = null; + Format inFormat = AslConverter.Format.NULL; + Format outFormat = AslConverter.Format.NULL; + + // Except for "--help", all arguments require a value currently. + // So just make sure we have an even number and + // then process them all two at a time. + if (args.length == 1 && "--help".equals(args[0])) { + showUsage(); + return; + } + if (args.length % 2 != 0) { + throw new IllegalArgumentException("Argument is missing corresponding value"); + } + for (int i = 0; i < args.length - 1; i += 2) { + final String arg = args[i].trim(); + final String argValue = args[i + 1].trim(); + if ("--in-path".equals(arg)) { + inFile = argValue; + } else if ("--out-path".equals(arg)) { + outFile = argValue; + } else if ("--in-format".equals(arg)) { + inFormat = getFormat(argValue); + } else if ("--out-format".equals(arg)) { + outFormat = getFormat(argValue); + } else { + throw new IllegalArgumentException("Unknown argument: " + arg); + } + } + + if (inFile == null) { + throw new IllegalArgumentException("input file is required"); + } + + if (outFile == null) { + throw new IllegalArgumentException("output file is required"); + } + + if (inFormat == AslConverter.Format.NULL) { + throw new IllegalArgumentException("input format is required"); + } + + if (outFormat == AslConverter.Format.NULL) { + throw new IllegalArgumentException("output format is required"); + } + + System.out.println("in path: " + inFile); + System.out.println("out path: " + outFile); + System.out.println("in format: " + inFormat); + System.out.println("out format: " + outFormat); + + var asl = AslConverter.readFromStream(new FileInputStream(inFile), inFormat); + AslConverter.writeToStream(new FileOutputStream(outFile), asl, outFormat); + } + + private static Format getFormat(String argValue) { + if ("hr".equals(argValue)) { + return AslConverter.Format.HUMAN_READABLE; + } else if ("od".equals(argValue)) { + return AslConverter.Format.ON_DEVICE; + } else { + return AslConverter.Format.NULL; + } + } + + private static void showUsage() { + System.err.println( + "Usage: aslgen --in-path [input-file] --out-path [output-file] --in-format [hr|od]" + + " --out-format [hr|od]"); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java new file mode 100644 index 000000000000..191f38d3df80 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2024 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.asllib; + +import com.android.asllib.marshallable.AndroidSafetyLabel; +import com.android.asllib.marshallable.AndroidSafetyLabelFactory; +import com.android.asllib.util.MalformedXmlException; +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +public class AslConverter { + public enum Format { + NULL, + HUMAN_READABLE, + ON_DEVICE; + } + + /** Reads a {@link AndroidSafetyLabel} from an {@link InputStream}. */ + // TODO(b/329902686): Support parsing from on-device. + public static AndroidSafetyLabel readFromStream(InputStream in, Format format) + throws IOException, ParserConfigurationException, SAXException, MalformedXmlException { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + Document document = factory.newDocumentBuilder().parse(in); + + switch (format) { + case HUMAN_READABLE: + Element appMetadataBundles = + XmlUtils.getSingleChildElement( + document, XmlUtils.HR_TAG_APP_METADATA_BUNDLES, true); + + return new AndroidSafetyLabelFactory() + .createFromHrElements(XmlUtils.listOf(appMetadataBundles)); + case ON_DEVICE: + Element bundleEle = + XmlUtils.getSingleChildElement(document, XmlUtils.OD_TAG_BUNDLE, true); + return new AndroidSafetyLabelFactory() + .createFromOdElements(XmlUtils.listOf(bundleEle)); + default: + throw new IllegalStateException("Unrecognized input format."); + } + } + + /** Reads a {@link AndroidSafetyLabel} from a String. */ + public static AndroidSafetyLabel readFromString(String in, Format format) + throws IOException, ParserConfigurationException, SAXException, MalformedXmlException { + InputStream stream = new ByteArrayInputStream(in.getBytes(StandardCharsets.UTF_8)); + return readFromStream(stream, format); + } + + /** Write the content of the {@link AndroidSafetyLabel} to a {@link OutputStream}. */ + // TODO(b/329902686): Support outputting human-readable format. + public static void writeToStream( + OutputStream out, AndroidSafetyLabel asl, AslConverter.Format format) + throws IOException, ParserConfigurationException, TransformerException { + var docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + var document = docBuilder.newDocument(); + + switch (format) { + case HUMAN_READABLE: + for (var child : asl.toHrDomElements(document)) { + document.appendChild(child); + } + break; + case ON_DEVICE: + for (var child : asl.toOdDomElements(document)) { + document.appendChild(child); + } + break; + default: + throw new IllegalStateException("Unrecognized input format."); + } + + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer = transformerFactory.newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + StreamResult streamResult = new StreamResult(out); // out + DOMSource domSource = new DOMSource(document); + transformer.transform(domSource, streamResult); + } + + /** Get the content of the {@link AndroidSafetyLabel} as String. */ + public static String getXmlAsString(AndroidSafetyLabel asl, AslConverter.Format format) + throws IOException, ParserConfigurationException, TransformerException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + writeToStream(out, asl, format); + return out.toString(StandardCharsets.UTF_8); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java new file mode 100644 index 000000000000..72140a17297c --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.List; + +public class AndroidSafetyLabel implements AslMarshallable { + + private final Long mVersion; + private final SystemAppSafetyLabel mSystemAppSafetyLabel; + private final SafetyLabels mSafetyLabels; + private final TransparencyInfo mTransparencyInfo; + + public SafetyLabels getSafetyLabels() { + return mSafetyLabels; + } + + public AndroidSafetyLabel( + Long version, + SystemAppSafetyLabel systemAppSafetyLabel, + SafetyLabels safetyLabels, + TransparencyInfo transparencyInfo) { + this.mVersion = version; + this.mSystemAppSafetyLabel = systemAppSafetyLabel; + this.mSafetyLabels = safetyLabels; + this.mTransparencyInfo = transparencyInfo; + } + + /** Creates an on-device DOM element from an {@link AndroidSafetyLabel} */ + @Override + public List<Element> toOdDomElements(Document doc) { + Element aslEle = doc.createElement(XmlUtils.OD_TAG_BUNDLE); + aslEle.appendChild(XmlUtils.createOdLongEle(doc, XmlUtils.OD_NAME_VERSION, mVersion)); + if (mSafetyLabels != null) { + XmlUtils.appendChildren(aslEle, mSafetyLabels.toOdDomElements(doc)); + } + if (mSystemAppSafetyLabel != null) { + XmlUtils.appendChildren(aslEle, mSystemAppSafetyLabel.toOdDomElements(doc)); + } + if (mTransparencyInfo != null) { + XmlUtils.appendChildren(aslEle, mTransparencyInfo.toOdDomElements(doc)); + } + return XmlUtils.listOf(aslEle); + } + + /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ + @Override + public List<Element> toHrDomElements(Document doc) { + Element aslEle = doc.createElement(XmlUtils.HR_TAG_APP_METADATA_BUNDLES); + aslEle.setAttribute(XmlUtils.HR_ATTR_VERSION, String.valueOf(mVersion)); + if (mSafetyLabels != null) { + XmlUtils.appendChildren(aslEle, mSafetyLabels.toHrDomElements(doc)); + } + if (mSystemAppSafetyLabel != null) { + XmlUtils.appendChildren(aslEle, mSystemAppSafetyLabel.toHrDomElements(doc)); + } + if (mTransparencyInfo != null) { + XmlUtils.appendChildren(aslEle, mTransparencyInfo.toHrDomElements(doc)); + } + return XmlUtils.listOf(aslEle); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java new file mode 100644 index 000000000000..c53cbbf99a46 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.MalformedXmlException; +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Element; + +import java.util.List; + +public class AndroidSafetyLabelFactory implements AslMarshallableFactory<AndroidSafetyLabel> { + + /** Creates an {@link AndroidSafetyLabel} from human-readable DOM element */ + @Override + public AndroidSafetyLabel createFromHrElements(List<Element> appMetadataBundles) + throws MalformedXmlException { + Element appMetadataBundlesEle = XmlUtils.getSingleElement(appMetadataBundles); + long version = XmlUtils.tryGetVersion(appMetadataBundlesEle); + + Element safetyLabelsEle = + XmlUtils.getSingleChildElement( + appMetadataBundlesEle, XmlUtils.HR_TAG_SAFETY_LABELS, false); + SafetyLabels safetyLabels = + new SafetyLabelsFactory().createFromHrElements(XmlUtils.listOf(safetyLabelsEle)); + + Element systemAppSafetyLabelEle = + XmlUtils.getSingleChildElement( + appMetadataBundlesEle, XmlUtils.HR_TAG_SYSTEM_APP_SAFETY_LABEL, false); + SystemAppSafetyLabel systemAppSafetyLabel = + new SystemAppSafetyLabelFactory() + .createFromHrElements(XmlUtils.listOf(systemAppSafetyLabelEle)); + + Element transparencyInfoEle = + XmlUtils.getSingleChildElement( + appMetadataBundlesEle, XmlUtils.HR_TAG_TRANSPARENCY_INFO, false); + TransparencyInfo transparencyInfo = + new TransparencyInfoFactory() + .createFromHrElements(XmlUtils.listOf(transparencyInfoEle)); + + return new AndroidSafetyLabel( + version, systemAppSafetyLabel, safetyLabels, transparencyInfo); + } + + /** Creates an {@link AndroidSafetyLabel} from on-device DOM elements */ + @Override + public AndroidSafetyLabel createFromOdElements(List<Element> elements) + throws MalformedXmlException { + Element bundleEle = XmlUtils.getSingleElement(elements); + Long version = XmlUtils.getOdLongEle(bundleEle, XmlUtils.OD_NAME_VERSION, true); + + Element safetyLabelsEle = + XmlUtils.getOdPbundleWithName(bundleEle, XmlUtils.OD_NAME_SAFETY_LABELS, false); + SafetyLabels safetyLabels = + new SafetyLabelsFactory().createFromOdElements(XmlUtils.listOf(safetyLabelsEle)); + + Element systemAppSafetyLabelEle = + XmlUtils.getOdPbundleWithName( + bundleEle, XmlUtils.OD_NAME_SYSTEM_APP_SAFETY_LABEL, false); + SystemAppSafetyLabel systemAppSafetyLabel = + new SystemAppSafetyLabelFactory() + .createFromOdElements(XmlUtils.listOf(systemAppSafetyLabelEle)); + + Element transparencyInfoEle = + XmlUtils.getOdPbundleWithName(bundleEle, XmlUtils.OD_NAME_TRANSPARENCY_INFO, false); + TransparencyInfo transparencyInfo = + new TransparencyInfoFactory() + .createFromOdElements(XmlUtils.listOf(transparencyInfoEle)); + + return new AndroidSafetyLabel( + version, systemAppSafetyLabel, safetyLabels, transparencyInfo); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java new file mode 100644 index 000000000000..129733ebc1b6 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.List; + +/** AppInfo representation */ +public class AppInfo implements AslMarshallable { + private final String mTitle; + private final String mDescription; + private final Boolean mContainsAds; + private final Boolean mObeyAps; + private final Boolean mAdsFingerprinting; + private final Boolean mSecurityFingerprinting; + private final String mPrivacyPolicy; + private final List<String> mSecurityEndpoints; + private final List<String> mFirstPartyEndpoints; + private final List<String> mServiceProviderEndpoints; + private final String mCategory; + private final String mEmail; + private final String mWebsite; + + public AppInfo( + String title, + String description, + Boolean containsAds, + Boolean obeyAps, + Boolean adsFingerprinting, + Boolean securityFingerprinting, + String privacyPolicy, + List<String> securityEndpoints, + List<String> firstPartyEndpoints, + List<String> serviceProviderEndpoints, + String category, + String email, + String website) { + this.mTitle = title; + this.mDescription = description; + this.mContainsAds = containsAds; + this.mObeyAps = obeyAps; + this.mAdsFingerprinting = adsFingerprinting; + this.mSecurityFingerprinting = securityFingerprinting; + this.mPrivacyPolicy = privacyPolicy; + this.mSecurityEndpoints = securityEndpoints; + this.mFirstPartyEndpoints = firstPartyEndpoints; + this.mServiceProviderEndpoints = serviceProviderEndpoints; + this.mCategory = category; + this.mEmail = email; + this.mWebsite = website; + } + + /** Creates an on-device DOM element from the {@link SafetyLabels}. */ + @Override + public List<Element> toOdDomElements(Document doc) { + Element appInfoEle = XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_APP_INFO); + if (this.mTitle != null) { + appInfoEle.appendChild(XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_TITLE, mTitle)); + } + if (this.mDescription != null) { + appInfoEle.appendChild( + XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_DESCRIPTION, mDescription)); + } + if (this.mContainsAds != null) { + appInfoEle.appendChild( + XmlUtils.createOdBooleanEle(doc, XmlUtils.OD_NAME_CONTAINS_ADS, mContainsAds)); + } + if (this.mObeyAps != null) { + appInfoEle.appendChild( + XmlUtils.createOdBooleanEle(doc, XmlUtils.OD_NAME_OBEY_APS, mObeyAps)); + } + if (this.mAdsFingerprinting != null) { + appInfoEle.appendChild( + XmlUtils.createOdBooleanEle( + doc, XmlUtils.OD_NAME_ADS_FINGERPRINTING, mAdsFingerprinting)); + } + if (this.mSecurityFingerprinting != null) { + appInfoEle.appendChild( + XmlUtils.createOdBooleanEle( + doc, + XmlUtils.OD_NAME_SECURITY_FINGERPRINTING, + mSecurityFingerprinting)); + } + if (this.mPrivacyPolicy != null) { + appInfoEle.appendChild( + XmlUtils.createOdStringEle( + doc, XmlUtils.OD_NAME_PRIVACY_POLICY, mPrivacyPolicy)); + } + if (this.mSecurityEndpoints != null) { + appInfoEle.appendChild( + XmlUtils.createOdArray( + doc, + XmlUtils.OD_TAG_STRING_ARRAY, + XmlUtils.OD_NAME_SECURITY_ENDPOINT, + mSecurityEndpoints)); + } + if (this.mFirstPartyEndpoints != null) { + appInfoEle.appendChild( + XmlUtils.createOdArray( + doc, + XmlUtils.OD_TAG_STRING_ARRAY, + XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINT, + mFirstPartyEndpoints)); + } + if (this.mServiceProviderEndpoints != null) { + appInfoEle.appendChild( + XmlUtils.createOdArray( + doc, + XmlUtils.OD_TAG_STRING_ARRAY, + XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINT, + mServiceProviderEndpoints)); + } + if (this.mCategory != null) { + appInfoEle.appendChild( + XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_CATEGORY, this.mCategory)); + } + if (this.mEmail != null) { + appInfoEle.appendChild( + XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_EMAIL, this.mEmail)); + } + if (this.mWebsite != null) { + appInfoEle.appendChild( + XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_WEBSITE, this.mWebsite)); + } + return XmlUtils.listOf(appInfoEle); + } + + /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ + @Override + public List<Element> toHrDomElements(Document doc) { + Element appInfoEle = doc.createElement(XmlUtils.HR_TAG_APP_INFO); + if (this.mTitle != null) { + appInfoEle.setAttribute(XmlUtils.HR_ATTR_TITLE, this.mTitle); + } + if (this.mDescription != null) { + appInfoEle.setAttribute(XmlUtils.HR_ATTR_DESCRIPTION, this.mDescription); + } + if (this.mContainsAds != null) { + appInfoEle.setAttribute( + XmlUtils.HR_ATTR_CONTAINS_ADS, String.valueOf(this.mContainsAds)); + } + if (this.mObeyAps != null) { + appInfoEle.setAttribute(XmlUtils.HR_ATTR_OBEY_APS, String.valueOf(this.mObeyAps)); + } + if (this.mAdsFingerprinting != null) { + appInfoEle.setAttribute( + XmlUtils.HR_ATTR_ADS_FINGERPRINTING, String.valueOf(this.mAdsFingerprinting)); + } + if (this.mSecurityFingerprinting != null) { + appInfoEle.setAttribute( + XmlUtils.HR_ATTR_SECURITY_FINGERPRINTING, + String.valueOf(this.mSecurityFingerprinting)); + } + if (this.mPrivacyPolicy != null) { + appInfoEle.setAttribute(XmlUtils.HR_ATTR_PRIVACY_POLICY, this.mPrivacyPolicy); + } + if (this.mSecurityEndpoints != null) { + appInfoEle.setAttribute( + XmlUtils.HR_ATTR_SECURITY_ENDPOINTS, String.join("|", this.mSecurityEndpoints)); + } + if (this.mFirstPartyEndpoints != null) { + appInfoEle.setAttribute( + XmlUtils.HR_ATTR_FIRST_PARTY_ENDPOINTS, + String.join("|", this.mFirstPartyEndpoints)); + } + if (this.mServiceProviderEndpoints != null) { + appInfoEle.setAttribute( + XmlUtils.HR_ATTR_SERVICE_PROVIDER_ENDPOINTS, + String.join("|", this.mServiceProviderEndpoints)); + } + if (this.mCategory != null) { + appInfoEle.setAttribute(XmlUtils.HR_ATTR_CATEGORY, this.mCategory); + } + if (this.mEmail != null) { + appInfoEle.setAttribute(XmlUtils.HR_ATTR_EMAIL, this.mEmail); + } + if (this.mWebsite != null) { + appInfoEle.setAttribute(XmlUtils.HR_ATTR_WEBSITE, this.mWebsite); + } + return XmlUtils.listOf(appInfoEle); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java new file mode 100644 index 000000000000..c5069619e069 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.AslgenUtil; +import com.android.asllib.util.MalformedXmlException; +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Element; + +import java.util.List; + +public class AppInfoFactory implements AslMarshallableFactory<AppInfo> { + + /** Creates a {@link AppInfo} from the human-readable DOM element. */ + @Override + public AppInfo createFromHrElements(List<Element> elements) throws MalformedXmlException { + Element appInfoEle = XmlUtils.getSingleElement(elements); + if (appInfoEle == null) { + AslgenUtil.logI("No AppInfo found in hr format."); + return null; + } + + String title = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_TITLE, true); + String description = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_DESCRIPTION, true); + Boolean containsAds = XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_CONTAINS_ADS, true); + Boolean obeyAps = XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_OBEY_APS, true); + Boolean adsFingerprinting = + XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_ADS_FINGERPRINTING, true); + Boolean securityFingerprinting = + XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_SECURITY_FINGERPRINTING, true); + String privacyPolicy = + XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_PRIVACY_POLICY, true); + List<String> securityEndpoints = + XmlUtils.getPipelineSplitAttr( + appInfoEle, XmlUtils.HR_ATTR_SECURITY_ENDPOINTS, true); + List<String> firstPartyEndpoints = + XmlUtils.getPipelineSplitAttr( + appInfoEle, XmlUtils.HR_ATTR_FIRST_PARTY_ENDPOINTS, true); + List<String> serviceProviderEndpoints = + XmlUtils.getPipelineSplitAttr( + appInfoEle, XmlUtils.HR_ATTR_SERVICE_PROVIDER_ENDPOINTS, true); + String category = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_CATEGORY, true); + String email = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_EMAIL, true); + String website = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_WEBSITE, false); + + return new AppInfo( + title, + description, + containsAds, + obeyAps, + adsFingerprinting, + securityFingerprinting, + privacyPolicy, + securityEndpoints, + firstPartyEndpoints, + serviceProviderEndpoints, + category, + email, + website); + } + + /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ + @Override + public AppInfo createFromOdElements(List<Element> elements) throws MalformedXmlException { + Element appInfoEle = XmlUtils.getSingleElement(elements); + if (appInfoEle == null) { + AslgenUtil.logI("No AppInfo found in od format."); + return null; + } + + String title = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_TITLE, true); + String description = + XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_DESCRIPTION, true); + Boolean containsAds = + XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_CONTAINS_ADS, true); + Boolean obeyAps = XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_OBEY_APS, true); + Boolean adsFingerprinting = + XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_ADS_FINGERPRINTING, true); + Boolean securityFingerprinting = + XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_SECURITY_FINGERPRINTING, true); + String privacyPolicy = + XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_PRIVACY_POLICY, true); + List<String> securityEndpoints = + XmlUtils.getOdStringArray(appInfoEle, XmlUtils.OD_NAME_SECURITY_ENDPOINT, true); + List<String> firstPartyEndpoints = + XmlUtils.getOdStringArray(appInfoEle, XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINT, true); + List<String> serviceProviderEndpoints = + XmlUtils.getOdStringArray( + appInfoEle, XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINT, true); + String category = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_CATEGORY, true); + String email = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_EMAIL, true); + String website = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_WEBSITE, false); + + return new AppInfo( + title, + description, + containsAds, + obeyAps, + adsFingerprinting, + securityFingerprinting, + privacyPolicy, + securityEndpoints, + firstPartyEndpoints, + serviceProviderEndpoints, + category, + email, + website); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java new file mode 100644 index 000000000000..0a70e7d0d74b --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.List; + +public interface AslMarshallable { + + /** Creates the on-device DOM elements from the AslMarshallable Java Object. */ + List<Element> toOdDomElements(Document doc); + + /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ + List<Element> toHrDomElements(Document doc); +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java new file mode 100644 index 000000000000..39582900f3a0 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.MalformedXmlException; + +import org.w3c.dom.Element; + +import java.util.List; + +public interface AslMarshallableFactory<T extends AslMarshallable> { + + /** Creates an {@link AslMarshallableFactory} from human-readable DOM elements */ + T createFromHrElements(List<Element> elements) throws MalformedXmlException; + + /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ + T createFromOdElements(List<Element> elements) throws MalformedXmlException; +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java new file mode 100644 index 000000000000..c16d18b34360 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.DataCategoryConstants; +import com.android.asllib.util.DataTypeConstants; +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Data usage category representation containing one or more {@link DataType}. Valid category keys + * are defined in {@link DataCategoryConstants}, each category has a valid set of types {@link + * DataType}, which are mapped in {@link DataTypeConstants} + */ +public class DataCategory implements AslMarshallable { + private final String mCategoryName; + private final Map<String, DataType> mDataTypes; + + public DataCategory(String categoryName, Map<String, DataType> dataTypes) { + this.mCategoryName = categoryName; + this.mDataTypes = dataTypes; + } + + public DataCategory(String categoryName) { + this.mCategoryName = categoryName; + this.mDataTypes = new LinkedHashMap<String, DataType>(); + } + + public String getCategoryName() { + return mCategoryName; + } + + /** Return the type {@link Map} of String type key to {@link DataType} */ + + public Map<String, DataType> getDataTypes() { + return mDataTypes; + } + + /** Creates on-device DOM element(s) from the {@link DataCategory}. */ + @Override + public List<Element> toOdDomElements(Document doc) { + Element dataCategoryEle = XmlUtils.createPbundleEleWithName(doc, this.getCategoryName()); + for (DataType dataType : mDataTypes.values()) { + XmlUtils.appendChildren(dataCategoryEle, dataType.toOdDomElements(doc)); + } + return XmlUtils.listOf(dataCategoryEle); + } + + /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ + @Override + public List<Element> toHrDomElements(Document doc) { + throw new IllegalStateException( + "Turning DataCategory or DataType into human-readable DOM elements requires" + + " visibility into parent elements. The logic resides in DataLabels."); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java new file mode 100644 index 000000000000..724416285acd --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.DataTypeConstants; +import com.android.asllib.util.MalformedXmlException; +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Element; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class DataCategoryFactory { + /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ + public DataCategory createFromOdElements(List<Element> elements) throws MalformedXmlException { + Element dataCategoryEle = XmlUtils.getSingleElement(elements); + Map<String, DataType> dataTypeMap = new LinkedHashMap<String, DataType>(); + String categoryName = dataCategoryEle.getAttribute(XmlUtils.OD_ATTR_NAME); + var odDataTypes = XmlUtils.asElementList(dataCategoryEle.getChildNodes()); + for (Element odDataTypeEle : odDataTypes) { + String dataTypeName = odDataTypeEle.getAttribute(XmlUtils.OD_ATTR_NAME); + if (!DataTypeConstants.getValidDataTypes().containsKey(categoryName)) { + throw new MalformedXmlException( + String.format("Unrecognized data category %s", categoryName)); + } + if (!DataTypeConstants.getValidDataTypes().get(categoryName).contains(dataTypeName)) { + throw new MalformedXmlException( + String.format( + "Unrecognized data type name %s for category %s", + dataTypeName, categoryName)); + } + dataTypeMap.put( + dataTypeName, + new DataTypeFactory().createFromOdElements(XmlUtils.listOf(odDataTypeEle))); + } + + return new DataCategory(categoryName, dataTypeMap); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java new file mode 100644 index 000000000000..ba0e3db52027 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.DataCategoryConstants; +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.List; +import java.util.Map; + +/** + * Data label representation with data shared and data collected maps containing zero or more {@link + * DataCategory} + */ +public class DataLabels implements AslMarshallable { + private final Map<String, DataCategory> mDataCollected; + private final Map<String, DataCategory> mDataShared; + + public DataLabels( + Map<String, DataCategory> dataCollected, + Map<String, DataCategory> dataShared) { + mDataCollected = dataCollected; + mDataShared = dataShared; + } + + /** + * Returns the data collected {@link Map} of {@link DataCategoryConstants} to {@link + * DataCategory} + */ + public Map<String, DataCategory> getDataCollected() { + return mDataCollected; + } + + /** + * Returns the data shared {@link Map} of {@link DataCategoryConstants} to {@link DataCategory} + */ + public Map<String, DataCategory> getDataShared() { + return mDataShared; + } + + /** Gets the on-device DOM element for the {@link DataLabels}. */ + @Override + public List<Element> toOdDomElements(Document doc) { + Element dataLabelsEle = + XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_DATA_LABELS); + + maybeAppendDataUsages(doc, dataLabelsEle, mDataCollected, XmlUtils.OD_NAME_DATA_COLLECTED); + maybeAppendDataUsages(doc, dataLabelsEle, mDataShared, XmlUtils.OD_NAME_DATA_SHARED); + + return XmlUtils.listOf(dataLabelsEle); + } + + /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ + @Override + public List<Element> toHrDomElements(Document doc) { + Element dataLabelsEle = doc.createElement(XmlUtils.HR_TAG_DATA_LABELS); + maybeAppendHrDataUsages( + doc, dataLabelsEle, mDataCollected, XmlUtils.HR_TAG_DATA_COLLECTED, false); + maybeAppendHrDataUsages( + doc, dataLabelsEle, mDataCollected, XmlUtils.HR_TAG_DATA_COLLECTED_EPHEMERAL, true); + maybeAppendHrDataUsages( + doc, dataLabelsEle, mDataShared, XmlUtils.HR_TAG_DATA_SHARED, false); + return XmlUtils.listOf(dataLabelsEle); + } + + private void maybeAppendDataUsages( + Document doc, + Element dataLabelsEle, + Map<String, DataCategory> dataCategoriesMap, + String dataUsageTypeName) { + if (dataCategoriesMap.isEmpty()) { + return; + } + Element dataUsageEle = XmlUtils.createPbundleEleWithName(doc, dataUsageTypeName); + + for (String dataCategoryName : dataCategoriesMap.keySet()) { + Element dataCategoryEle = XmlUtils.createPbundleEleWithName(doc, dataCategoryName); + DataCategory dataCategory = dataCategoriesMap.get(dataCategoryName); + for (String dataTypeName : dataCategory.getDataTypes().keySet()) { + DataType dataType = dataCategory.getDataTypes().get(dataTypeName); + XmlUtils.appendChildren(dataCategoryEle, dataType.toOdDomElements(doc)); + } + dataUsageEle.appendChild(dataCategoryEle); + } + dataLabelsEle.appendChild(dataUsageEle); + } + + private void maybeAppendHrDataUsages( + Document doc, + Element dataLabelsEle, + Map<String, DataCategory> dataCategoriesMap, + String dataUsageTypeName, + boolean ephemeral) { + if (dataCategoriesMap.isEmpty()) { + return; + } + for (String dataCategoryName : dataCategoriesMap.keySet()) { + DataCategory dataCategory = dataCategoriesMap.get(dataCategoryName); + for (String dataTypeName : dataCategory.getDataTypes().keySet()) { + DataType dataType = dataCategory.getDataTypes().get(dataTypeName); + if (ephemeral + != (dataType.getEphemeral() != null ? dataType.getEphemeral() : false)) { + continue; + } + + Element hrDataTypeEle = doc.createElement(dataUsageTypeName); + hrDataTypeEle.setAttribute( + XmlUtils.HR_ATTR_DATA_TYPE, + dataCategoryName + XmlUtils.DATA_TYPE_SEPARATOR + dataTypeName); + XmlUtils.maybeSetHrBoolAttr( + hrDataTypeEle, + XmlUtils.HR_ATTR_IS_COLLECTION_OPTIONAL, + dataType.getIsCollectionOptional()); + XmlUtils.maybeSetHrBoolAttr( + hrDataTypeEle, + XmlUtils.HR_ATTR_IS_SHARING_OPTIONAL, + dataType.getIsSharingOptional()); + hrDataTypeEle.setAttribute( + XmlUtils.HR_ATTR_PURPOSES, + String.join( + "|", + dataType.getPurposes().stream() + .map(DataType.Purpose::toString) + .toList())); + dataLabelsEle.appendChild(hrDataTypeEle); + } + } + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java new file mode 100644 index 000000000000..c4d88761835a --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.AslgenUtil; +import com.android.asllib.util.DataCategoryConstants; +import com.android.asllib.util.DataTypeConstants; +import com.android.asllib.util.MalformedXmlException; +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Element; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class DataLabelsFactory implements AslMarshallableFactory<DataLabels> { + + /** Creates a {@link DataLabels} from the human-readable DOM element. */ + @Override + public DataLabels createFromHrElements(List<Element> elements) throws MalformedXmlException { + Element ele = XmlUtils.getSingleElement(elements); + if (ele == null) { + AslgenUtil.logI("Found no DataLabels in hr format."); + return null; + } + Map<String, DataCategory> dataCollected = + getDataCategoriesWithTag(ele, XmlUtils.HR_TAG_DATA_COLLECTED, false); + Map<String, DataCategory> dataCollectedEphemeral = + getDataCategoriesWithTag(ele, XmlUtils.HR_TAG_DATA_COLLECTED_EPHEMERAL, true); + Map<String, DataCategory> dataShared = + getDataCategoriesWithTag(ele, XmlUtils.HR_TAG_DATA_SHARED, null); + + for (String dataCollectedEphemeralDataCategoryKey : dataCollectedEphemeral.keySet()) { + DataCategory dataCategoryEphemeral = + dataCollectedEphemeral.get(dataCollectedEphemeralDataCategoryKey); + for (String dataCollectedEphemeralDataTypeKey : + dataCategoryEphemeral.getDataTypes().keySet()) { + if (dataCollected.containsKey(dataCollectedEphemeralDataCategoryKey) + && dataCollected + .get(dataCollectedEphemeralDataCategoryKey) + .getDataTypes() + .containsKey(dataCollectedEphemeralDataTypeKey)) { + throw new MalformedXmlException( + String.format( + "Duplicate entries in data-collected and" + + " data-collected-ephemeral: %s %s", + dataCollectedEphemeralDataCategoryKey, + dataCollectedEphemeralDataTypeKey)); + } + + if (!dataCollected.containsKey(dataCollectedEphemeralDataCategoryKey)) { + dataCollected.put( + dataCollectedEphemeralDataCategoryKey, + new DataCategory(dataCollectedEphemeralDataCategoryKey)); + } + DataType dataTypeEphemeral = + dataCategoryEphemeral.getDataTypes().get(dataCollectedEphemeralDataTypeKey); + dataCollected + .get(dataCollectedEphemeralDataCategoryKey) + .getDataTypes() + .put(dataCollectedEphemeralDataTypeKey, dataTypeEphemeral); + } + } + DataLabels dataLabels = new DataLabels(dataCollected, dataShared); + + validateIsXOptional(dataLabels); + return dataLabels; + } + + /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ + @Override + public DataLabels createFromOdElements(List<Element> elements) throws MalformedXmlException { + Element dataLabelsEle = XmlUtils.getSingleElement(elements); + if (dataLabelsEle == null) { + AslgenUtil.logI("Found no DataLabels in od format."); + return null; + } + Map<String, DataCategory> dataCollected = + getOdDataCategoriesWithTag(dataLabelsEle, XmlUtils.OD_NAME_DATA_COLLECTED); + Map<String, DataCategory> dataShared = + getOdDataCategoriesWithTag(dataLabelsEle, XmlUtils.OD_NAME_DATA_SHARED); + DataLabels dataLabels = new DataLabels(dataCollected, dataShared); + validateIsXOptional(dataLabels); + return dataLabels; + } + + private static Map<String, DataCategory> getOdDataCategoriesWithTag( + Element dataLabelsEle, String dataCategoryUsageTypeTag) throws MalformedXmlException { + Map<String, DataCategory> dataCategoryMap = new LinkedHashMap<String, DataCategory>(); + Element dataUsageEle = + XmlUtils.getOdPbundleWithName(dataLabelsEle, dataCategoryUsageTypeTag, false); + if (dataUsageEle == null) { + return dataCategoryMap; + } + List<Element> dataCategoryEles = XmlUtils.asElementList(dataUsageEle.getChildNodes()); + for (Element dataCategoryEle : dataCategoryEles) { + String dataCategoryName = dataCategoryEle.getAttribute(XmlUtils.OD_ATTR_NAME); + DataCategory dataCategory = + new DataCategoryFactory().createFromOdElements(List.of(dataCategoryEle)); + dataCategoryMap.put(dataCategoryName, dataCategory); + } + return dataCategoryMap; + } + + private static Map<String, DataCategory> getDataCategoriesWithTag( + Element dataLabelsEle, String dataCategoryUsageTypeTag, Boolean ephemeral) + throws MalformedXmlException { + List<Element> dataUsedElements = + XmlUtils.getChildrenByTagName(dataLabelsEle, dataCategoryUsageTypeTag); + Map<String, DataCategory> dataCategoryMap = new LinkedHashMap<String, DataCategory>(); + + for (int i = 0; i < dataUsedElements.size(); i++) { + Element dataUsedEle = dataUsedElements.get(i); + String dataCategoryAndTypeCombinedStr = + dataUsedEle.getAttribute(XmlUtils.HR_ATTR_DATA_TYPE); + String[] strs = dataCategoryAndTypeCombinedStr.split(XmlUtils.DATA_TYPE_SEPARATOR); + if (strs.length != 2) { + throw new MalformedXmlException( + String.format( + "Could not parse human-readable data type string (expecting" + + " substring of _data_type_): %s", + dataCategoryAndTypeCombinedStr)); + } + String dataCategoryName = strs[0]; + String dataTypeName = strs[1]; + + if (!DataCategoryConstants.getValidDataCategories().contains(dataCategoryName)) { + throw new MalformedXmlException( + String.format("Unrecognized category name: %s", dataCategoryName)); + } + if (!DataTypeConstants.getValidDataTypes() + .get(dataCategoryName) + .contains(dataTypeName)) { + throw new MalformedXmlException( + String.format( + "Unrecognized data type name %s for category %s", + dataTypeName, dataCategoryName)); + } + + if (!dataCategoryMap.containsKey(dataCategoryName)) { + dataCategoryMap.put(dataCategoryName, new DataCategory(dataCategoryName)); + } + dataCategoryMap + .get(dataCategoryName) + .getDataTypes() + .put( + dataTypeName, + new DataTypeFactory().createFromHrElements(dataUsedEle, ephemeral)); + } + + return dataCategoryMap; + } + + private void validateIsXOptional(DataLabels dataLabels) throws MalformedXmlException { + // Validate booleans such as isCollectionOptional, isSharingOptional. + for (DataCategory dataCategory : dataLabels.getDataCollected().values()) { + for (DataType dataType : dataCategory.getDataTypes().values()) { + if (dataType.getIsSharingOptional() != null) { + throw new MalformedXmlException( + String.format( + "isSharingOptional was unexpectedly defined on a DataType" + + " belonging to data collected: %s", + dataType.getDataTypeName())); + } + } + } + for (DataCategory dataCategory : dataLabels.getDataShared().values()) { + for (DataType dataType : dataCategory.getDataTypes().values()) { + if (dataType.getIsCollectionOptional() != null) { + throw new MalformedXmlException( + String.format( + "isCollectionOptional was unexpectedly defined on a DataType" + + " belonging to data shared: %s", + dataType.getDataTypeName())); + } + } + } + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java new file mode 100644 index 000000000000..d2326d10e176 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * Data usage type representation. Types are specific to a {@link DataCategory} and contains + * metadata related to the data usage purpose. + */ +public class DataType implements AslMarshallable { + + public enum Purpose { + APP_FUNCTIONALITY(1), + ANALYTICS(2), + DEVELOPER_COMMUNICATIONS(3), + FRAUD_PREVENTION_SECURITY(4), + ADVERTISING(5), + PERSONALIZATION(6), + ACCOUNT_MANAGEMENT(7); + + private final int mValue; + + Purpose(int value) { + this.mValue = value; + } + + /** Get the int value associated with the Purpose. */ + public int getValue() { + return mValue; + } + + /** Get the Purpose associated with the int value. */ + public static Purpose forValue(int value) { + for (Purpose e : values()) { + if (e.getValue() == value) { + return e; + } + } + throw new IllegalArgumentException("No Purpose enum for value: " + value); + } + + /** Get the Purpose associated with the human-readable String. */ + public static Purpose forString(String s) { + for (Purpose e : values()) { + if (e.toString().equals(s)) { + return e; + } + } + throw new IllegalArgumentException("No Purpose enum for str: " + s); + } + + /** Human-readable String representation of Purpose. */ + public String toString() { + return this.name().toLowerCase(); + } + } + + @Override + public boolean equals(Object obj) { + if (obj == null || obj.getClass() != this.getClass()) { + return false; + } + DataType objAsDataType = (DataType) obj; + return Objects.equals(this.mDataTypeName, objAsDataType.mDataTypeName) + && Objects.equals( + new HashSet<>(this.mPurposes), new HashSet<>(objAsDataType.mPurposes)) + && Objects.equals(this.mIsCollectionOptional, objAsDataType.mIsCollectionOptional) + && Objects.equals(this.mIsSharingOptional, objAsDataType.mIsSharingOptional) + && Objects.equals(this.mEphemeral, objAsDataType.mEphemeral); + } + + @Override + public int hashCode() { + int result = 1; + int prime = 31; + result = + (prime * result) + (this.mDataTypeName != null ? this.mDataTypeName.hashCode() : 0); + result = + (prime * result) + + (this.mPurposes != null ? new HashSet<>(this.mPurposes).hashCode() : 0); + result = + (prime * result) + + (this.mIsCollectionOptional != null + ? this.mIsCollectionOptional.hashCode() + : 0); + result = + (prime * result) + + (this.mIsSharingOptional != null + ? this.mIsSharingOptional.hashCode() + : 0); + result = (prime * result) + (this.mEphemeral != null ? this.mEphemeral.hashCode() : 0); + return result; + } + + private final String mDataTypeName; + + private final List<Purpose> mPurposes; + private final Boolean mIsCollectionOptional; + private final Boolean mIsSharingOptional; + private final Boolean mEphemeral; + + public DataType( + String dataTypeName, + List<Purpose> purposes, + Boolean isCollectionOptional, + Boolean isSharingOptional, + Boolean ephemeral) { + this.mDataTypeName = dataTypeName; + this.mPurposes = purposes; + this.mIsCollectionOptional = isCollectionOptional; + this.mIsSharingOptional = isSharingOptional; + this.mEphemeral = ephemeral; + } + + public String getDataTypeName() { + return mDataTypeName; + } + + /** + * Returns {@link Set} of valid {@link Integer} purposes for using the associated data category + * and type + */ + public List<Purpose> getPurposes() { + return mPurposes; + } + + /** + * For data-collected, returns {@code true} if data usage is user optional and {@code false} if + * data usage is required. Should return {@code null} for data-accessed and data-shared. + */ + public Boolean getIsCollectionOptional() { + return mIsCollectionOptional; + } + + /** + * For data-shared, returns {@code true} if data usage is user optional and {@code false} if + * data usage is required. Should return {@code null} for data-accessed and data-collected. + */ + public Boolean getIsSharingOptional() { + return mIsSharingOptional; + } + + /** + * For data-collected, returns {@code true} if data usage is user optional and {@code false} if + * data usage is processed ephemerally. Should return {@code null} for data-shared. + */ + public Boolean getEphemeral() { + return mEphemeral; + } + + @Override + public List<Element> toOdDomElements(Document doc) { + Element dataTypeEle = XmlUtils.createPbundleEleWithName(doc, this.getDataTypeName()); + if (!this.getPurposes().isEmpty()) { + dataTypeEle.appendChild( + XmlUtils.createOdArray( + doc, + XmlUtils.OD_TAG_INT_ARRAY, + XmlUtils.OD_NAME_PURPOSES, + this.getPurposes().stream() + .map(p -> String.valueOf(p.getValue())) + .toList())); + } + + maybeAddBoolToOdElement( + doc, + dataTypeEle, + this.getIsCollectionOptional(), + XmlUtils.OD_NAME_IS_COLLECTION_OPTIONAL); + maybeAddBoolToOdElement( + doc, + dataTypeEle, + this.getIsSharingOptional(), + XmlUtils.OD_NAME_IS_SHARING_OPTIONAL); + maybeAddBoolToOdElement(doc, dataTypeEle, this.getEphemeral(), XmlUtils.OD_NAME_EPHEMERAL); + return XmlUtils.listOf(dataTypeEle); + } + + /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ + @Override + public List<Element> toHrDomElements(Document doc) { + throw new IllegalStateException( + "Turning DataCategory or DataType into human-readable DOM elements requires" + + " visibility into parent elements. The logic resides in DataLabels."); + } + + private static void maybeAddBoolToOdElement( + Document doc, Element parentEle, Boolean b, String odName) { + if (b == null) { + return; + } + Element ele = XmlUtils.createOdBooleanEle(doc, odName, b); + parentEle.appendChild(ele); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java new file mode 100644 index 000000000000..a5559d801349 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.MalformedXmlException; +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Element; + +import java.util.HashSet; +import java.util.List; +import java.util.stream.Collectors; + +public class DataTypeFactory { + /** Creates a {@link DataType} from the human-readable DOM element. */ + public DataType createFromHrElements(Element hrDataTypeEle, Boolean ephemeral) + throws MalformedXmlException { + String dataCategoryAndTypeCombinedStr = + hrDataTypeEle.getAttribute(XmlUtils.HR_ATTR_DATA_TYPE); + String[] strs = dataCategoryAndTypeCombinedStr.split(XmlUtils.DATA_TYPE_SEPARATOR); + if (strs.length != 2) { + throw new MalformedXmlException( + String.format( + "Could not parse human-readable data type string (expecting substring" + + " of _data_type_): %s", + dataCategoryAndTypeCombinedStr)); + } + String dataTypeName = strs[1]; + + List<DataType.Purpose> purposes = + XmlUtils.getPipelineSplitAttr(hrDataTypeEle, XmlUtils.HR_ATTR_PURPOSES, true) + .stream() + .map(DataType.Purpose::forString) + .collect(Collectors.toList()); + if (purposes.isEmpty()) { + throw new MalformedXmlException(String.format("Found no purpose in: %s", dataTypeName)); + } + if (new HashSet<>(purposes).size() != purposes.size()) { + throw new MalformedXmlException( + String.format("Found non-unique purposes in: %s", dataTypeName)); + } + Boolean isCollectionOptional = + XmlUtils.getBoolAttr(hrDataTypeEle, XmlUtils.HR_ATTR_IS_COLLECTION_OPTIONAL, false); + Boolean isSharingOptional = + XmlUtils.getBoolAttr(hrDataTypeEle, XmlUtils.HR_ATTR_IS_SHARING_OPTIONAL, false); + // Boolean ephemeral = XmlUtils.getBoolAttr(hrDataTypeEle, XmlUtils.HR_ATTR_EPHEMERAL, + // false); + return new DataType( + dataTypeName, purposes, isCollectionOptional, isSharingOptional, ephemeral); + } + + /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ + public DataType createFromOdElements(List<Element> elements) throws MalformedXmlException { + Element odDataTypeEle = XmlUtils.getSingleElement(elements); + String dataTypeName = odDataTypeEle.getAttribute(XmlUtils.OD_ATTR_NAME); + List<Integer> purposeInts = + XmlUtils.getOdIntArray(odDataTypeEle, XmlUtils.OD_NAME_PURPOSES, true); + List<DataType.Purpose> purposes = + purposeInts.stream().map(DataType.Purpose::forValue).collect(Collectors.toList()); + if (purposes.isEmpty()) { + throw new MalformedXmlException(String.format("Found no purpose in: %s", dataTypeName)); + } + if (new HashSet<>(purposes).size() != purposes.size()) { + throw new MalformedXmlException( + String.format("Found non-unique purposes in: %s", dataTypeName)); + } + Boolean isCollectionOptional = + XmlUtils.getOdBoolEle( + odDataTypeEle, XmlUtils.OD_NAME_IS_COLLECTION_OPTIONAL, false); + Boolean isSharingOptional = + XmlUtils.getOdBoolEle(odDataTypeEle, XmlUtils.OD_NAME_IS_SHARING_OPTIONAL, false); + Boolean ephemeral = XmlUtils.getOdBoolEle(odDataTypeEle, XmlUtils.OD_NAME_EPHEMERAL, false); + + return new DataType( + dataTypeName, purposes, isCollectionOptional, isSharingOptional, ephemeral); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java new file mode 100644 index 000000000000..94fad9607880 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.List; + +/** DeveloperInfo representation */ +public class DeveloperInfo implements AslMarshallable { + public enum DeveloperRelationship { + OEM(0), + ODM(1), + SOC(2), + OTA(3), + CARRIER(4), + AOSP(5), + OTHER(6); + + private final int mValue; + + DeveloperRelationship(int value) { + this.mValue = value; + } + + /** Get the int value associated with the DeveloperRelationship. */ + public int getValue() { + return mValue; + } + + /** Get the DeveloperRelationship associated with the int value. */ + public static DeveloperInfo.DeveloperRelationship forValue(int value) { + for (DeveloperInfo.DeveloperRelationship e : values()) { + if (e.getValue() == value) { + return e; + } + } + throw new IllegalArgumentException("No DeveloperRelationship enum for value: " + value); + } + + /** Get the DeveloperRelationship associated with the human-readable String. */ + public static DeveloperInfo.DeveloperRelationship forString(String s) { + for (DeveloperInfo.DeveloperRelationship e : values()) { + if (e.toString().equals(s)) { + return e; + } + } + throw new IllegalArgumentException("No DeveloperRelationship enum for str: " + s); + } + + /** Human-readable String representation of DeveloperRelationship. */ + public String toString() { + return this.name().toLowerCase(); + } + } + + private final String mName; + private final String mEmail; + private final String mAddress; + private final String mCountryRegion; + private final DeveloperRelationship mDeveloperRelationship; + private final String mWebsite; + private final String mAppDeveloperRegistryId; + + public DeveloperInfo( + String name, + String email, + String address, + String countryRegion, + DeveloperRelationship developerRelationship, + String website, + String appDeveloperRegistryId) { + this.mName = name; + this.mEmail = email; + this.mAddress = address; + this.mCountryRegion = countryRegion; + this.mDeveloperRelationship = developerRelationship; + this.mWebsite = website; + this.mAppDeveloperRegistryId = appDeveloperRegistryId; + } + + /** Creates an on-device DOM element from the {@link SafetyLabels}. */ + @Override + public List<Element> toOdDomElements(Document doc) { + Element developerInfoEle = + XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_DEVELOPER_INFO); + if (mName != null) { + developerInfoEle.appendChild( + XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_NAME, mName)); + } + if (mEmail != null) { + developerInfoEle.appendChild( + XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_EMAIL, mEmail)); + } + if (mAddress != null) { + developerInfoEle.appendChild( + XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_ADDRESS, mAddress)); + } + if (mCountryRegion != null) { + developerInfoEle.appendChild( + XmlUtils.createOdStringEle( + doc, XmlUtils.OD_NAME_COUNTRY_REGION, mCountryRegion)); + } + if (mDeveloperRelationship != null) { + developerInfoEle.appendChild( + XmlUtils.createOdLongEle( + doc, + XmlUtils.OD_NAME_DEVELOPER_RELATIONSHIP, + mDeveloperRelationship.getValue())); + } + if (mWebsite != null) { + developerInfoEle.appendChild( + XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_WEBSITE, mWebsite)); + } + if (mAppDeveloperRegistryId != null) { + developerInfoEle.appendChild( + XmlUtils.createOdStringEle( + doc, + XmlUtils.OD_NAME_APP_DEVELOPER_REGISTRY_ID, + mAppDeveloperRegistryId)); + } + + return XmlUtils.listOf(developerInfoEle); + } + + /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ + @Override + public List<Element> toHrDomElements(Document doc) { + Element developerInfoEle = doc.createElement(XmlUtils.HR_TAG_DEVELOPER_INFO); + if (mName != null) { + developerInfoEle.setAttribute(XmlUtils.HR_ATTR_NAME, mName); + } + if (mEmail != null) { + developerInfoEle.setAttribute(XmlUtils.HR_ATTR_EMAIL, mEmail); + } + if (mAddress != null) { + developerInfoEle.setAttribute(XmlUtils.HR_ATTR_ADDRESS, mAddress); + } + if (mCountryRegion != null) { + developerInfoEle.setAttribute(XmlUtils.HR_ATTR_COUNTRY_REGION, mCountryRegion); + } + if (mDeveloperRelationship != null) { + developerInfoEle.setAttribute( + XmlUtils.HR_ATTR_DEVELOPER_RELATIONSHIP, mDeveloperRelationship.toString()); + } + if (mWebsite != null) { + developerInfoEle.setAttribute(XmlUtils.HR_ATTR_WEBSITE, mWebsite); + } + if (mAppDeveloperRegistryId != null) { + developerInfoEle.setAttribute( + XmlUtils.HR_ATTR_APP_DEVELOPER_REGISTRY_ID, mAppDeveloperRegistryId); + } + + return XmlUtils.listOf(developerInfoEle); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java new file mode 100644 index 000000000000..0f3b41cd5d1a --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.AslgenUtil; +import com.android.asllib.util.MalformedXmlException; +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Element; + +import java.util.List; + +public class DeveloperInfoFactory implements AslMarshallableFactory<DeveloperInfo> { + + /** Creates a {@link DeveloperInfo} from the human-readable DOM element. */ + @Override + public DeveloperInfo createFromHrElements(List<Element> elements) throws MalformedXmlException { + Element developerInfoEle = XmlUtils.getSingleElement(elements); + if (developerInfoEle == null) { + AslgenUtil.logI("No DeveloperInfo found in hr format."); + return null; + } + String name = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_NAME, true); + String email = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_EMAIL, true); + String address = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_ADDRESS, true); + String countryRegion = + XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_COUNTRY_REGION, true); + DeveloperInfo.DeveloperRelationship developerRelationship = + DeveloperInfo.DeveloperRelationship.forString( + XmlUtils.getStringAttr( + developerInfoEle, XmlUtils.HR_ATTR_DEVELOPER_RELATIONSHIP, true)); + String website = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_WEBSITE, false); + String appDeveloperRegistryId = + XmlUtils.getStringAttr( + developerInfoEle, XmlUtils.HR_ATTR_APP_DEVELOPER_REGISTRY_ID, false); + + return new DeveloperInfo( + name, + email, + address, + countryRegion, + developerRelationship, + website, + appDeveloperRegistryId); + } + + /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ + @Override + public DeveloperInfo createFromOdElements(List<Element> elements) throws MalformedXmlException { + Element developerInfoEle = XmlUtils.getSingleElement(elements); + if (developerInfoEle == null) { + AslgenUtil.logI("No DeveloperInfo found in od format."); + return null; + } + String name = XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_NAME, true); + String email = XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_EMAIL, true); + String address = XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_ADDRESS, true); + String countryRegion = + XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_COUNTRY_REGION, true); + DeveloperInfo.DeveloperRelationship developerRelationship = + DeveloperInfo.DeveloperRelationship.forValue( + (int) + (long) + XmlUtils.getOdLongEle( + developerInfoEle, + XmlUtils.OD_NAME_DEVELOPER_RELATIONSHIP, + true)); + String website = XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_WEBSITE, false); + String appDeveloperRegistryId = + XmlUtils.getOdStringEle( + developerInfoEle, XmlUtils.OD_NAME_APP_DEVELOPER_REGISTRY_ID, false); + + return new DeveloperInfo( + name, + email, + address, + countryRegion, + developerRelationship, + website, + appDeveloperRegistryId); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java new file mode 100644 index 000000000000..6af80715f7c1 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.List; + +/** Safety Label representation containing zero or more {@link DataCategory} for data shared */ +public class SafetyLabels implements AslMarshallable { + + private final Long mVersion; + private final DataLabels mDataLabels; + private final SecurityLabels mSecurityLabels; + private final ThirdPartyVerification mThirdPartyVerification; + + public SafetyLabels( + Long version, + DataLabels dataLabels, + SecurityLabels securityLabels, + ThirdPartyVerification thirdPartyVerification) { + this.mVersion = version; + this.mDataLabels = dataLabels; + this.mSecurityLabels = securityLabels; + this.mThirdPartyVerification = thirdPartyVerification; + } + + /** Returns the data label for the safety label */ + public DataLabels getDataLabel() { + return mDataLabels; + } + + /** Gets the version of the {@link SafetyLabels}. */ + public Long getVersion() { + return mVersion; + } + + /** Creates an on-device DOM element from the {@link SafetyLabels}. */ + @Override + public List<Element> toOdDomElements(Document doc) { + Element safetyLabelsEle = + XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_SAFETY_LABELS); + safetyLabelsEle.appendChild( + XmlUtils.createOdLongEle(doc, XmlUtils.OD_NAME_VERSION, mVersion)); + if (mDataLabels != null) { + XmlUtils.appendChildren(safetyLabelsEle, mDataLabels.toOdDomElements(doc)); + } + if (mSecurityLabels != null) { + XmlUtils.appendChildren(safetyLabelsEle, mSecurityLabels.toOdDomElements(doc)); + } + if (mThirdPartyVerification != null) { + XmlUtils.appendChildren(safetyLabelsEle, mThirdPartyVerification.toOdDomElements(doc)); + } + return XmlUtils.listOf(safetyLabelsEle); + } + + /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ + @Override + public List<Element> toHrDomElements(Document doc) { + Element safetyLabelsEle = doc.createElement(XmlUtils.HR_TAG_SAFETY_LABELS); + safetyLabelsEle.setAttribute(XmlUtils.HR_ATTR_VERSION, String.valueOf(mVersion)); + + if (mDataLabels != null) { + XmlUtils.appendChildren(safetyLabelsEle, mDataLabels.toHrDomElements(doc)); + } + if (mSecurityLabels != null) { + XmlUtils.appendChildren(safetyLabelsEle, mSecurityLabels.toHrDomElements(doc)); + } + if (mThirdPartyVerification != null) { + XmlUtils.appendChildren(safetyLabelsEle, mThirdPartyVerification.toHrDomElements(doc)); + } + return XmlUtils.listOf(safetyLabelsEle); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java new file mode 100644 index 000000000000..2644b435311b --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.AslgenUtil; +import com.android.asllib.util.MalformedXmlException; +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Element; + +import java.util.List; + +public class SafetyLabelsFactory implements AslMarshallableFactory<SafetyLabels> { + + /** Creates a {@link SafetyLabels} from the human-readable DOM element. */ + @Override + public SafetyLabels createFromHrElements(List<Element> elements) throws MalformedXmlException { + Element safetyLabelsEle = XmlUtils.getSingleElement(elements); + if (safetyLabelsEle == null) { + AslgenUtil.logI("No SafetyLabels found in hr format."); + return null; + } + long version = XmlUtils.tryGetVersion(safetyLabelsEle); + + DataLabels dataLabels = + new DataLabelsFactory() + .createFromHrElements( + XmlUtils.listOf( + XmlUtils.getSingleChildElement( + safetyLabelsEle, + XmlUtils.HR_TAG_DATA_LABELS, + false))); + SecurityLabels securityLabels = + new SecurityLabelsFactory() + .createFromHrElements( + XmlUtils.listOf( + XmlUtils.getSingleChildElement( + safetyLabelsEle, + XmlUtils.HR_TAG_SECURITY_LABELS, + false))); + ThirdPartyVerification thirdPartyVerification = + new ThirdPartyVerificationFactory() + .createFromHrElements( + XmlUtils.listOf( + XmlUtils.getSingleChildElement( + safetyLabelsEle, + XmlUtils.HR_TAG_THIRD_PARTY_VERIFICATION, + false))); + return new SafetyLabels(version, dataLabels, securityLabels, thirdPartyVerification); + } + + /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ + @Override + public SafetyLabels createFromOdElements(List<Element> elements) throws MalformedXmlException { + Element safetyLabelsEle = XmlUtils.getSingleElement(elements); + if (safetyLabelsEle == null) { + AslgenUtil.logI("No SafetyLabels found in od format."); + return null; + } + Long version = XmlUtils.getOdLongEle(safetyLabelsEle, XmlUtils.OD_NAME_VERSION, true); + + DataLabels dataLabels = + new DataLabelsFactory() + .createFromOdElements( + XmlUtils.listOf( + XmlUtils.getOdPbundleWithName( + safetyLabelsEle, + XmlUtils.OD_NAME_DATA_LABELS, + false))); + SecurityLabels securityLabels = + new SecurityLabelsFactory() + .createFromOdElements( + XmlUtils.listOf( + XmlUtils.getOdPbundleWithName( + safetyLabelsEle, + XmlUtils.OD_NAME_SECURITY_LABELS, + false))); + ThirdPartyVerification thirdPartyVerification = + new ThirdPartyVerificationFactory() + .createFromOdElements( + XmlUtils.listOf( + XmlUtils.getOdPbundleWithName( + safetyLabelsEle, + XmlUtils.OD_NAME_THIRD_PARTY_VERIFICATION, + false))); + return new SafetyLabels(version, dataLabels, securityLabels, thirdPartyVerification); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java new file mode 100644 index 000000000000..48643ba0e3ab --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.List; + +/** Security Labels representation */ +public class SecurityLabels implements AslMarshallable { + + private final Boolean mIsDataDeletable; + private final Boolean mIsDataEncrypted; + + public SecurityLabels(Boolean isDataDeletable, Boolean isDataEncrypted) { + this.mIsDataDeletable = isDataDeletable; + this.mIsDataEncrypted = isDataEncrypted; + } + + /** Creates an on-device DOM element from the {@link SecurityLabels}. */ + @Override + public List<Element> toOdDomElements(Document doc) { + Element ele = XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_SECURITY_LABELS); + if (mIsDataDeletable != null) { + ele.appendChild( + XmlUtils.createOdBooleanEle( + doc, XmlUtils.OD_NAME_IS_DATA_DELETABLE, mIsDataDeletable)); + } + if (mIsDataEncrypted != null) { + ele.appendChild( + XmlUtils.createOdBooleanEle( + doc, XmlUtils.OD_NAME_IS_DATA_ENCRYPTED, mIsDataEncrypted)); + } + return XmlUtils.listOf(ele); + } + + /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ + @Override + public List<Element> toHrDomElements(Document doc) { + Element ele = doc.createElement(XmlUtils.HR_TAG_SECURITY_LABELS); + if (mIsDataDeletable != null) { + ele.setAttribute(XmlUtils.HR_ATTR_IS_DATA_DELETABLE, String.valueOf(mIsDataDeletable)); + } + if (mIsDataEncrypted != null) { + ele.setAttribute(XmlUtils.HR_ATTR_IS_DATA_ENCRYPTED, String.valueOf(mIsDataEncrypted)); + } + return XmlUtils.listOf(ele); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java new file mode 100644 index 000000000000..525a80388261 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.AslgenUtil; +import com.android.asllib.util.MalformedXmlException; +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Element; + +import java.util.List; + +public class SecurityLabelsFactory implements AslMarshallableFactory<SecurityLabels> { + + /** Creates a {@link SecurityLabels} from the human-readable DOM element. */ + @Override + public SecurityLabels createFromHrElements(List<Element> elements) + throws MalformedXmlException { + Element ele = XmlUtils.getSingleElement(elements); + if (ele == null) { + AslgenUtil.logI("No SecurityLabels found in hr format."); + return null; + } + Boolean isDataDeletable = + XmlUtils.getBoolAttr(ele, XmlUtils.HR_ATTR_IS_DATA_DELETABLE, false); + Boolean isDataEncrypted = + XmlUtils.getBoolAttr(ele, XmlUtils.HR_ATTR_IS_DATA_ENCRYPTED, false); + return new SecurityLabels(isDataDeletable, isDataEncrypted); + } + + /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ + @Override + public SecurityLabels createFromOdElements(List<Element> elements) + throws MalformedXmlException { + Element ele = XmlUtils.getSingleElement(elements); + if (ele == null) { + AslgenUtil.logI("No SecurityLabels found in od format."); + return null; + } + Boolean isDataDeletable = + XmlUtils.getOdBoolEle(ele, XmlUtils.OD_NAME_IS_DATA_DELETABLE, false); + Boolean isDataEncrypted = + XmlUtils.getOdBoolEle(ele, XmlUtils.OD_NAME_IS_DATA_ENCRYPTED, false); + return new SecurityLabels(isDataDeletable, isDataEncrypted); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java new file mode 100644 index 000000000000..242e7be66d76 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.List; + +/** Safety Label representation containing zero or more {@link DataCategory} for data shared */ +public class SystemAppSafetyLabel implements AslMarshallable { + + private final Boolean mDeclaration; + + public SystemAppSafetyLabel(Boolean d) { + this.mDeclaration = d; + } + + /** Creates an on-device DOM element from the {@link SystemAppSafetyLabel}. */ + @Override + public List<Element> toOdDomElements(Document doc) { + Element systemAppSafetyLabelEle = + XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_SYSTEM_APP_SAFETY_LABEL); + systemAppSafetyLabelEle.appendChild( + XmlUtils.createOdBooleanEle(doc, XmlUtils.OD_NAME_DECLARATION, mDeclaration)); + return XmlUtils.listOf(systemAppSafetyLabelEle); + } + + /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ + @Override + public List<Element> toHrDomElements(Document doc) { + Element systemAppSafetyLabelEle = + doc.createElement(XmlUtils.HR_TAG_SYSTEM_APP_SAFETY_LABEL); + XmlUtils.maybeSetHrBoolAttr( + systemAppSafetyLabelEle, XmlUtils.HR_ATTR_DECLARATION, mDeclaration); + return XmlUtils.listOf(systemAppSafetyLabelEle); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java new file mode 100644 index 000000000000..7f4aa7a3b690 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.AslgenUtil; +import com.android.asllib.util.MalformedXmlException; +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Element; + +import java.util.List; + +public class SystemAppSafetyLabelFactory implements AslMarshallableFactory<SystemAppSafetyLabel> { + + /** Creates a {@link SystemAppSafetyLabel} from the human-readable DOM element. */ + @Override + public SystemAppSafetyLabel createFromHrElements(List<Element> elements) + throws MalformedXmlException { + Element systemAppSafetyLabelEle = XmlUtils.getSingleElement(elements); + if (systemAppSafetyLabelEle == null) { + AslgenUtil.logI("No SystemAppSafetyLabel found in hr format."); + return null; + } + + Boolean declaration = + XmlUtils.getBoolAttr(systemAppSafetyLabelEle, XmlUtils.HR_ATTR_DECLARATION, true); + return new SystemAppSafetyLabel(declaration); + } + + /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ + @Override + public SystemAppSafetyLabel createFromOdElements(List<Element> elements) + throws MalformedXmlException { + Element systemAppSafetyLabelEle = XmlUtils.getSingleElement(elements); + if (systemAppSafetyLabelEle == null) { + AslgenUtil.logI("No SystemAppSafetyLabel found in od format."); + return null; + } + Boolean declaration = + XmlUtils.getOdBoolEle(systemAppSafetyLabelEle, XmlUtils.OD_NAME_DECLARATION, true); + return new SystemAppSafetyLabel(declaration); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java new file mode 100644 index 000000000000..d74f3f062513 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.List; + +/** ThirdPartyVerification representation. */ +public class ThirdPartyVerification implements AslMarshallable { + + private final String mUrl; + + public ThirdPartyVerification(String url) { + this.mUrl = url; + } + + /** Creates an on-device DOM element from the {@link ThirdPartyVerification}. */ + @Override + public List<Element> toOdDomElements(Document doc) { + Element ele = + XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_THIRD_PARTY_VERIFICATION); + ele.appendChild(XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_URL, mUrl)); + return XmlUtils.listOf(ele); + } + + /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ + @Override + public List<Element> toHrDomElements(Document doc) { + Element ele = doc.createElement(XmlUtils.HR_TAG_THIRD_PARTY_VERIFICATION); + ele.setAttribute(XmlUtils.HR_ATTR_URL, mUrl); + return XmlUtils.listOf(ele); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java new file mode 100644 index 000000000000..197e7aa77743 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.AslgenUtil; +import com.android.asllib.util.MalformedXmlException; +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Element; + +import java.util.List; + +public class ThirdPartyVerificationFactory + implements AslMarshallableFactory<ThirdPartyVerification> { + + /** Creates a {@link ThirdPartyVerification} from the human-readable DOM element. */ + @Override + public ThirdPartyVerification createFromHrElements(List<Element> elements) + throws MalformedXmlException { + Element ele = XmlUtils.getSingleElement(elements); + if (ele == null) { + AslgenUtil.logI("No ThirdPartyVerification found in hr format."); + return null; + } + + String url = XmlUtils.getStringAttr(ele, XmlUtils.HR_ATTR_URL, true); + return new ThirdPartyVerification(url); + } + + /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ + @Override + public ThirdPartyVerification createFromOdElements(List<Element> elements) + throws MalformedXmlException { + Element ele = XmlUtils.getSingleElement(elements); + if (ele == null) { + AslgenUtil.logI("No ThirdPartyVerification found in od format."); + return null; + } + + String url = XmlUtils.getOdStringEle(ele, XmlUtils.OD_NAME_URL, true); + return new ThirdPartyVerification(url); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java new file mode 100644 index 000000000000..6a8700a10d3f --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.List; + +/** TransparencyInfo representation containing {@link DeveloperInfo} and {@link AppInfo} */ +public class TransparencyInfo implements AslMarshallable { + + private final DeveloperInfo mDeveloperInfo; + private final AppInfo mAppInfo; + + public TransparencyInfo(DeveloperInfo developerInfo, AppInfo appInfo) { + this.mDeveloperInfo = developerInfo; + this.mAppInfo = appInfo; + } + + /** Gets the {@link DeveloperInfo} of the {@link TransparencyInfo}. */ + public DeveloperInfo getDeveloperInfo() { + return mDeveloperInfo; + } + + /** Gets the {@link AppInfo} of the {@link TransparencyInfo}. */ + public AppInfo getAppInfo() { + return mAppInfo; + } + + /** Creates an on-device DOM element from the {@link TransparencyInfo}. */ + @Override + public List<Element> toOdDomElements(Document doc) { + Element transparencyInfoEle = + XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_TRANSPARENCY_INFO); + if (mDeveloperInfo != null) { + XmlUtils.appendChildren(transparencyInfoEle, mDeveloperInfo.toOdDomElements(doc)); + } + if (mAppInfo != null) { + XmlUtils.appendChildren(transparencyInfoEle, mAppInfo.toOdDomElements(doc)); + } + return XmlUtils.listOf(transparencyInfoEle); + } + + /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ + @Override + public List<Element> toHrDomElements(Document doc) { + Element transparencyInfoEle = doc.createElement(XmlUtils.HR_TAG_TRANSPARENCY_INFO); + if (mDeveloperInfo != null) { + XmlUtils.appendChildren(transparencyInfoEle, mDeveloperInfo.toHrDomElements(doc)); + } + if (mAppInfo != null) { + XmlUtils.appendChildren(transparencyInfoEle, mAppInfo.toHrDomElements(doc)); + } + return XmlUtils.listOf(transparencyInfoEle); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java new file mode 100644 index 000000000000..94c564087918 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2024 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.asllib.marshallable; + +import com.android.asllib.util.AslgenUtil; +import com.android.asllib.util.MalformedXmlException; +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Element; + +import java.util.List; + +public class TransparencyInfoFactory implements AslMarshallableFactory<TransparencyInfo> { + + /** Creates a {@link TransparencyInfo} from the human-readable DOM element. */ + @Override + public TransparencyInfo createFromHrElements(List<Element> elements) + throws MalformedXmlException { + Element transparencyInfoEle = XmlUtils.getSingleElement(elements); + if (transparencyInfoEle == null) { + AslgenUtil.logI("No TransparencyInfo found in hr format."); + return null; + } + + Element developerInfoEle = + XmlUtils.getSingleChildElement( + transparencyInfoEle, XmlUtils.HR_TAG_DEVELOPER_INFO, false); + DeveloperInfo developerInfo = + new DeveloperInfoFactory().createFromHrElements(XmlUtils.listOf(developerInfoEle)); + + Element appInfoEle = + XmlUtils.getSingleChildElement( + transparencyInfoEle, XmlUtils.HR_TAG_APP_INFO, false); + AppInfo appInfo = new AppInfoFactory().createFromHrElements(XmlUtils.listOf(appInfoEle)); + + return new TransparencyInfo(developerInfo, appInfo); + } + + /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ + @Override + public TransparencyInfo createFromOdElements(List<Element> elements) + throws MalformedXmlException { + Element transparencyInfoEle = XmlUtils.getSingleElement(elements); + if (transparencyInfoEle == null) { + AslgenUtil.logI("No TransparencyInfo found in od format."); + return null; + } + + Element developerInfoEle = + XmlUtils.getOdPbundleWithName( + transparencyInfoEle, XmlUtils.OD_NAME_DEVELOPER_INFO, false); + DeveloperInfo developerInfo = + new DeveloperInfoFactory().createFromOdElements(XmlUtils.listOf(developerInfoEle)); + + Element appInfoEle = + XmlUtils.getOdPbundleWithName( + transparencyInfoEle, XmlUtils.OD_NAME_APP_INFO, false); + AppInfo appInfo = new AppInfoFactory().createFromOdElements(XmlUtils.listOf(appInfoEle)); + + return new TransparencyInfo(developerInfo, appInfo); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/AslgenUtil.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/AslgenUtil.java new file mode 100644 index 000000000000..7d5421545091 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/AslgenUtil.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2024 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.asllib.util; + +public class AslgenUtil { + private static final String ASLGEN_TAG = "ASLGEN"; + + /** Log info. */ + public static void logI(String s) { + System.out.println(String.format("%s -- INFO: %s", ASLGEN_TAG, s)); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/DataCategoryConstants.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/DataCategoryConstants.java new file mode 100644 index 000000000000..b5ae54c5bc00 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/DataCategoryConstants.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2024 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.asllib.util; + +import com.android.asllib.marshallable.DataCategory; +import com.android.asllib.marshallable.DataType; +import com.android.asllib.marshallable.SafetyLabels; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * Constants for determining valid {@link String} data types for usage within {@link SafetyLabels}, + * {@link DataCategory}, and {@link DataType} + */ +public class DataCategoryConstants { + + public static final String CATEGORY_PERSONAL = "personal"; + public static final String CATEGORY_FINANCIAL = "financial"; + public static final String CATEGORY_LOCATION = "location"; + public static final String CATEGORY_EMAIL_TEXT_MESSAGE = "email_text_message"; + public static final String CATEGORY_PHOTO_VIDEO = "photo_video"; + public static final String CATEGORY_AUDIO = "audio"; + public static final String CATEGORY_STORAGE = "storage"; + public static final String CATEGORY_HEALTH_FITNESS = "health_fitness"; + public static final String CATEGORY_CONTACTS = "contacts"; + public static final String CATEGORY_CALENDAR = "calendar"; + public static final String CATEGORY_IDENTIFIERS = "identifiers"; + public static final String CATEGORY_APP_PERFORMANCE = "app_performance"; + public static final String CATEGORY_ACTIONS_IN_APP = "actions_in_app"; + public static final String CATEGORY_SEARCH_AND_BROWSING = "search_and_browsing"; + + /** Set of valid categories */ + public static final Set<String> VALID_CATEGORIES = + Collections.unmodifiableSet( + new HashSet<>( + Arrays.asList( + CATEGORY_PERSONAL, + CATEGORY_FINANCIAL, + CATEGORY_LOCATION, + CATEGORY_EMAIL_TEXT_MESSAGE, + CATEGORY_PHOTO_VIDEO, + CATEGORY_AUDIO, + CATEGORY_STORAGE, + CATEGORY_HEALTH_FITNESS, + CATEGORY_CONTACTS, + CATEGORY_CALENDAR, + CATEGORY_IDENTIFIERS, + CATEGORY_APP_PERFORMANCE, + CATEGORY_ACTIONS_IN_APP, + CATEGORY_SEARCH_AND_BROWSING))); + + /** Returns {@link Set} of valid {@link String} category keys */ + public static Set<String> getValidDataCategories() { + return VALID_CATEGORIES; + } + + private DataCategoryConstants() { + /* do nothing - hide constructor */ + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/DataTypeConstants.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/DataTypeConstants.java new file mode 100644 index 000000000000..358d575c1d56 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/DataTypeConstants.java @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2024 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.asllib.util; + +import com.android.asllib.marshallable.DataCategory; +import com.android.asllib.marshallable.DataType; +import com.android.asllib.marshallable.SafetyLabels; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +import java.util.Map; +import java.util.Set; + +/** + * Constants for determining valid {@link String} data types for usage within {@link SafetyLabels}, + * {@link DataCategory}, and {@link DataType} + */ +public class DataTypeConstants { + /** Data types for {@link DataCategoryConstants.CATEGORY_PERSONAL} */ + public static final String TYPE_NAME = "name"; + + public static final String TYPE_EMAIL_ADDRESS = "email_address"; + public static final String TYPE_PHYSICAL_ADDRESS = "physical_address"; + public static final String TYPE_PHONE_NUMBER = "phone_number"; + public static final String TYPE_RACE_ETHNICITY = "race_ethnicity"; + public static final String TYPE_POLITICAL_OR_RELIGIOUS_BELIEFS = + "political_or_religious_beliefs"; + public static final String TYPE_SEXUAL_ORIENTATION_OR_GENDER_IDENTITY = + "sexual_orientation_or_gender_identity"; + public static final String TYPE_PERSONAL_IDENTIFIERS = "personal_identifiers"; + public static final String TYPE_OTHER = "other"; + + /** Data types for {@link DataCategoryConstants.CATEGORY_FINANCIAL} */ + public static final String TYPE_CARD_BANK_ACCOUNT = "card_bank_account"; + + public static final String TYPE_PURCHASE_HISTORY = "purchase_history"; + public static final String TYPE_CREDIT_SCORE = "credit_score"; + public static final String TYPE_FINANCIAL_OTHER = "other"; + + /** Data types for {@link DataCategoryConstants.CATEGORY_LOCATION} */ + public static final String TYPE_APPROX_LOCATION = "approx_location"; + + public static final String TYPE_PRECISE_LOCATION = "precise_location"; + + /** Data types for {@link DataCategoryConstants.CATEGORY_EMAIL_TEXT_MESSAGE} */ + public static final String TYPE_EMAILS = "emails"; + + public static final String TYPE_TEXT_MESSAGES = "text_messages"; + public static final String TYPE_EMAIL_TEXT_MESSAGE_OTHER = "other"; + + /** Data types for {@link DataCategoryConstants.CATEGORY_PHOTO_VIDEO} */ + public static final String TYPE_PHOTOS = "photos"; + + public static final String TYPE_VIDEOS = "videos"; + + /** Data types for {@link DataCategoryConstants.CATEGORY_AUDIO} */ + public static final String TYPE_SOUND_RECORDINGS = "sound_recordings"; + + public static final String TYPE_MUSIC_FILES = "music_files"; + public static final String TYPE_AUDIO_OTHER = "other"; + + /** Data types for {@link DataCategoryConstants.CATEGORY_STORAGE} */ + public static final String TYPE_FILES_DOCS = "files_docs"; + + /** Data types for {@link DataCategoryConstants.CATEGORY_HEALTH_FITNESS} */ + public static final String TYPE_HEALTH = "health"; + + public static final String TYPE_FITNESS = "fitness"; + + /** Data types for {@link DataCategoryConstants.CATEGORY_CONTACTS} */ + public static final String TYPE_CONTACTS = "contacts"; + + /** Data types for {@link DataCategoryConstants.CATEGORY_CALENDAR} */ + public static final String TYPE_CALENDAR = "calendar"; + + /** Data types for {@link DataCategoryConstants.CATEGORY_IDENTIFIERS} */ + public static final String TYPE_IDENTIFIERS_OTHER = "other"; + + /** Data types for {@link DataCategoryConstants.CATEGORY_APP_PERFORMANCE} */ + public static final String TYPE_CRASH_LOGS = "crash_logs"; + + public static final String TYPE_PERFORMANCE_DIAGNOSTICS = "performance_diagnostics"; + public static final String TYPE_APP_PERFORMANCE_OTHER = "other"; + + /** Data types for {@link DataCategoryConstants.CATEGORY_ACTIONS_IN_APP} */ + public static final String TYPE_USER_INTERACTION = "user_interaction"; + + public static final String TYPE_IN_APP_SEARCH_HISTORY = "in_app_search_history"; + public static final String TYPE_INSTALLED_APPS = "installed_apps"; + public static final String TYPE_USER_GENERATED_CONTENT = "user_generated_content"; + public static final String TYPE_ACTIONS_IN_APP_OTHER = "other"; + + /** Data types for {@link DataCategoryConstants.CATEGORY_SEARCH_AND_BROWSING} */ + public static final String TYPE_WEB_BROWSING_HISTORY = "web_browsing_history"; + + /** Set of valid categories */ + private static final Map<String, Set<String>> VALID_DATA_TYPES = + new ImmutableMap.Builder<String, Set<String>>() + .put( + DataCategoryConstants.CATEGORY_PERSONAL, + ImmutableSet.of( + DataTypeConstants.TYPE_NAME, + DataTypeConstants.TYPE_EMAIL_ADDRESS, + DataTypeConstants.TYPE_PHYSICAL_ADDRESS, + DataTypeConstants.TYPE_PHONE_NUMBER, + DataTypeConstants.TYPE_RACE_ETHNICITY, + DataTypeConstants.TYPE_POLITICAL_OR_RELIGIOUS_BELIEFS, + DataTypeConstants.TYPE_SEXUAL_ORIENTATION_OR_GENDER_IDENTITY, + DataTypeConstants.TYPE_PERSONAL_IDENTIFIERS, + DataTypeConstants.TYPE_OTHER)) + .put( + DataCategoryConstants.CATEGORY_FINANCIAL, + ImmutableSet.of( + DataTypeConstants.TYPE_CARD_BANK_ACCOUNT, + DataTypeConstants.TYPE_PURCHASE_HISTORY, + DataTypeConstants.TYPE_CREDIT_SCORE, + DataTypeConstants.TYPE_OTHER)) + .put( + DataCategoryConstants.CATEGORY_LOCATION, + ImmutableSet.of( + DataTypeConstants.TYPE_APPROX_LOCATION, + DataTypeConstants.TYPE_PRECISE_LOCATION)) + .put( + DataCategoryConstants.CATEGORY_EMAIL_TEXT_MESSAGE, + ImmutableSet.of( + DataTypeConstants.TYPE_EMAILS, + DataTypeConstants.TYPE_TEXT_MESSAGES, + DataTypeConstants.TYPE_OTHER)) + .put( + DataCategoryConstants.CATEGORY_PHOTO_VIDEO, + ImmutableSet.of( + DataTypeConstants.TYPE_PHOTOS, DataTypeConstants.TYPE_VIDEOS)) + .put( + DataCategoryConstants.CATEGORY_AUDIO, + ImmutableSet.of( + DataTypeConstants.TYPE_SOUND_RECORDINGS, + DataTypeConstants.TYPE_MUSIC_FILES, + DataTypeConstants.TYPE_OTHER)) + .put( + DataCategoryConstants.CATEGORY_STORAGE, + ImmutableSet.of(DataTypeConstants.TYPE_FILES_DOCS)) + .put( + DataCategoryConstants.CATEGORY_HEALTH_FITNESS, + ImmutableSet.of( + DataTypeConstants.TYPE_HEALTH, DataTypeConstants.TYPE_FITNESS)) + .put( + DataCategoryConstants.CATEGORY_CONTACTS, + ImmutableSet.of(DataTypeConstants.TYPE_CONTACTS)) + .put( + DataCategoryConstants.CATEGORY_CALENDAR, + ImmutableSet.of(DataTypeConstants.TYPE_CALENDAR)) + .put( + DataCategoryConstants.CATEGORY_IDENTIFIERS, + ImmutableSet.of(DataTypeConstants.TYPE_OTHER)) + .put( + DataCategoryConstants.CATEGORY_APP_PERFORMANCE, + ImmutableSet.of( + DataTypeConstants.TYPE_CRASH_LOGS, + DataTypeConstants.TYPE_PERFORMANCE_DIAGNOSTICS, + DataTypeConstants.TYPE_OTHER)) + .put( + DataCategoryConstants.CATEGORY_ACTIONS_IN_APP, + ImmutableSet.of( + DataTypeConstants.TYPE_USER_INTERACTION, + DataTypeConstants.TYPE_IN_APP_SEARCH_HISTORY, + DataTypeConstants.TYPE_INSTALLED_APPS, + DataTypeConstants.TYPE_USER_GENERATED_CONTENT, + DataTypeConstants.TYPE_OTHER)) + .put( + DataCategoryConstants.CATEGORY_SEARCH_AND_BROWSING, + ImmutableSet.of(DataTypeConstants.TYPE_WEB_BROWSING_HISTORY)) + .buildOrThrow(); + + /** Returns {@link Set} of valid {@link String} category keys */ + public static Map<String, Set<String>> getValidDataTypes() { + return VALID_DATA_TYPES; + } + + private DataTypeConstants() { + /* do nothing - hide constructor */ + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/MalformedXmlException.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/MalformedXmlException.java new file mode 100644 index 000000000000..216df56c453e --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/MalformedXmlException.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2024 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.asllib.util; + +public class MalformedXmlException extends Exception { + /** Constructs an {@code MalformedXmlException} with no detail message. */ + public MalformedXmlException() { + super(); + } + + /** + * Constructs an {@code MalformedXmlException} with the specified detail message. + * + * @param s the detail message. + */ + public MalformedXmlException(String s) { + super(s); + } +} diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java new file mode 100644 index 000000000000..97cbc3950490 --- /dev/null +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java @@ -0,0 +1,496 @@ +/* + * Copyright (C) 2024 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.asllib.util; + + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class XmlUtils { + public static final String DATA_TYPE_SEPARATOR = "_data_type_"; + + public static final String HR_TAG_APP_METADATA_BUNDLES = "app-metadata-bundles"; + public static final String HR_TAG_SYSTEM_APP_SAFETY_LABEL = "system-app-safety-label"; + public static final String HR_TAG_SAFETY_LABELS = "safety-labels"; + public static final String HR_TAG_TRANSPARENCY_INFO = "transparency-info"; + public static final String HR_TAG_DEVELOPER_INFO = "developer-info"; + public static final String HR_TAG_APP_INFO = "app-info"; + public static final String HR_TAG_DATA_LABELS = "data-labels"; + public static final String HR_TAG_SECURITY_LABELS = "security-labels"; + public static final String HR_TAG_THIRD_PARTY_VERIFICATION = "third-party-verification"; + public static final String HR_TAG_DATA_ACCESSED = "data-accessed"; + public static final String HR_TAG_DATA_COLLECTED = "data-collected"; + public static final String HR_TAG_DATA_COLLECTED_EPHEMERAL = "data-collected-ephemeral"; + public static final String HR_TAG_DATA_SHARED = "data-shared"; + public static final String HR_ATTR_NAME = "name"; + public static final String HR_ATTR_EMAIL = "email"; + public static final String HR_ATTR_ADDRESS = "address"; + public static final String HR_ATTR_COUNTRY_REGION = "countryRegion"; + public static final String HR_ATTR_DEVELOPER_RELATIONSHIP = "relationship"; + public static final String HR_ATTR_WEBSITE = "website"; + public static final String HR_ATTR_APP_DEVELOPER_REGISTRY_ID = "registryId"; + public static final String HR_ATTR_DATA_CATEGORY = "dataCategory"; + public static final String HR_ATTR_DATA_TYPE = "dataType"; + public static final String HR_ATTR_IS_COLLECTION_OPTIONAL = "isCollectionOptional"; + public static final String HR_ATTR_IS_SHARING_OPTIONAL = "isSharingOptional"; + public static final String HR_ATTR_IS_DATA_DELETABLE = "isDataDeletable"; + public static final String HR_ATTR_IS_DATA_ENCRYPTED = "isDataEncrypted"; + // public static final String HR_ATTR_EPHEMERAL = "ephemeral"; + public static final String HR_ATTR_PURPOSES = "purposes"; + public static final String HR_ATTR_VERSION = "version"; + public static final String HR_ATTR_URL = "url"; + public static final String HR_ATTR_DECLARATION = "declaration"; + public static final String HR_ATTR_TITLE = "title"; + public static final String HR_ATTR_DESCRIPTION = "description"; + public static final String HR_ATTR_CONTAINS_ADS = "containsAds"; + public static final String HR_ATTR_OBEY_APS = "obeyAps"; + public static final String HR_ATTR_ADS_FINGERPRINTING = "adsFingerprinting"; + public static final String HR_ATTR_SECURITY_FINGERPRINTING = "securityFingerprinting"; + public static final String HR_ATTR_PRIVACY_POLICY = "privacyPolicy"; + public static final String HR_ATTR_SECURITY_ENDPOINTS = "securityEndpoints"; + public static final String HR_ATTR_FIRST_PARTY_ENDPOINTS = "firstPartyEndpoints"; + public static final String HR_ATTR_SERVICE_PROVIDER_ENDPOINTS = "serviceProviderEndpoints"; + public static final String HR_ATTR_CATEGORY = "category"; + + public static final String OD_TAG_BUNDLE = "bundle"; + public static final String OD_TAG_PBUNDLE_AS_MAP = "pbundle_as_map"; + public static final String OD_TAG_BOOLEAN = "boolean"; + public static final String OD_TAG_LONG = "long"; + public static final String OD_TAG_STRING = "string"; + public static final String OD_TAG_INT_ARRAY = "int-array"; + public static final String OD_TAG_STRING_ARRAY = "string-array"; + public static final String OD_TAG_ITEM = "item"; + public static final String OD_ATTR_NAME = "name"; + public static final String OD_ATTR_VALUE = "value"; + public static final String OD_ATTR_NUM = "num"; + public static final String OD_NAME_SAFETY_LABELS = "safety_labels"; + public static final String OD_NAME_TRANSPARENCY_INFO = "transparency_info"; + public static final String OD_NAME_DEVELOPER_INFO = "developer_info"; + public static final String OD_NAME_NAME = "name"; + public static final String OD_NAME_EMAIL = "email"; + public static final String OD_NAME_ADDRESS = "address"; + public static final String OD_NAME_COUNTRY_REGION = "country_region"; + public static final String OD_NAME_DEVELOPER_RELATIONSHIP = "relationship"; + public static final String OD_NAME_WEBSITE = "website"; + public static final String OD_NAME_APP_DEVELOPER_REGISTRY_ID = "app_developer_registry_id"; + public static final String OD_NAME_APP_INFO = "app_info"; + public static final String OD_NAME_TITLE = "title"; + public static final String OD_NAME_DESCRIPTION = "description"; + public static final String OD_NAME_CONTAINS_ADS = "contains_ads"; + public static final String OD_NAME_OBEY_APS = "obey_aps"; + public static final String OD_NAME_ADS_FINGERPRINTING = "ads_fingerprinting"; + public static final String OD_NAME_SECURITY_FINGERPRINTING = "security_fingerprinting"; + public static final String OD_NAME_PRIVACY_POLICY = "privacy_policy"; + public static final String OD_NAME_SECURITY_ENDPOINT = "security_endpoint"; + public static final String OD_NAME_FIRST_PARTY_ENDPOINT = "first_party_endpoint"; + public static final String OD_NAME_SERVICE_PROVIDER_ENDPOINT = "service_provider_endpoint"; + public static final String OD_NAME_CATEGORY = "category"; + public static final String OD_NAME_VERSION = "version"; + public static final String OD_NAME_URL = "url"; + public static final String OD_NAME_DECLARATION = "declaration"; + public static final String OD_NAME_SYSTEM_APP_SAFETY_LABEL = "system_app_safety_label"; + public static final String OD_NAME_SECURITY_LABELS = "security_labels"; + public static final String OD_NAME_THIRD_PARTY_VERIFICATION = "third_party_verification"; + public static final String OD_NAME_DATA_LABELS = "data_labels"; + public static final String OD_NAME_DATA_ACCESSED = "data_accessed"; + public static final String OD_NAME_DATA_COLLECTED = "data_collected"; + public static final String OD_NAME_DATA_SHARED = "data_shared"; + public static final String OD_NAME_PURPOSES = "purposes"; + public static final String OD_NAME_IS_COLLECTION_OPTIONAL = "is_collection_optional"; + public static final String OD_NAME_IS_SHARING_OPTIONAL = "is_sharing_optional"; + public static final String OD_NAME_IS_DATA_DELETABLE = "is_data_deletable"; + public static final String OD_NAME_IS_DATA_ENCRYPTED = "is_data_encrypted"; + public static final String OD_NAME_EPHEMERAL = "ephemeral"; + + public static final String TRUE_STR = "true"; + public static final String FALSE_STR = "false"; + + /** Gets the top-level children with the tag name.. */ + public static List<Element> getChildrenByTagName(Node parentEle, String tagName) { + var elements = XmlUtils.asElementList(parentEle.getChildNodes()); + return elements.stream().filter(e -> e.getTagName().equals(tagName)).toList(); + } + + /** + * Gets the single {@link Element} within {@param parentEle} and having the {@param tagName}. + */ + public static Element getSingleChildElement(Node parentEle, String tagName, boolean required) + throws MalformedXmlException { + String parentTagNameForErrorMsg = + (parentEle instanceof Element) ? ((Element) parentEle).getTagName() : "Node"; + var elements = getChildrenByTagName(parentEle, tagName); + + if (elements.size() > 1) { + throw new MalformedXmlException( + String.format( + "Expected 1 %s in %s but got %s.", + tagName, parentTagNameForErrorMsg, elements.size())); + } else if (elements.isEmpty()) { + if (required) { + throw new MalformedXmlException( + String.format( + "Expected 1 %s in %s but got 0.", + tagName, parentTagNameForErrorMsg)); + } else { + return null; + } + } + return elements.get(0); + } + + /** Gets the single {@link Element} within {@param elements}. */ + public static Element getSingleElement(List<Element> elements) { + if (elements.size() != 1) { + throw new IllegalStateException( + String.format("Expected 1 element in list but got %s.", elements.size())); + } + return elements.get(0); + } + + /** Converts {@param nodeList} into List of {@link Element}. */ + public static List<Element> asElementList(NodeList nodeList) { + List<Element> elementList = new ArrayList<Element>(); + for (int i = 0; i < nodeList.getLength(); i++) { + var elementAsNode = nodeList.item(i); + if (elementAsNode instanceof Element) { + elementList.add(((Element) elementAsNode)); + } + } + return elementList; + } + + /** Appends {@param children} to the {@param ele}. */ + public static void appendChildren(Element ele, List<Element> children) { + for (Element c : children) { + ele.appendChild(c); + } + } + + /** Gets the Boolean from the String value. */ + private static Boolean fromString(String s) { + if (s == null) { + return null; + } + if (s.equals(TRUE_STR)) { + return true; + } else if (s.equals(FALSE_STR)) { + return false; + } + return null; + } + + /** Creates an on-device PBundle DOM Element with the given attribute name. */ + public static Element createPbundleEleWithName(Document doc, String name) { + var ele = doc.createElement(XmlUtils.OD_TAG_PBUNDLE_AS_MAP); + ele.setAttribute(XmlUtils.OD_ATTR_NAME, name); + return ele; + } + + /** Create an on-device Boolean DOM Element with the given attribute name. */ + public static Element createOdBooleanEle(Document doc, String name, boolean b) { + var ele = doc.createElement(XmlUtils.OD_TAG_BOOLEAN); + ele.setAttribute(XmlUtils.OD_ATTR_NAME, name); + ele.setAttribute(XmlUtils.OD_ATTR_VALUE, String.valueOf(b)); + return ele; + } + + /** Sets human-readable bool attribute if non-null. */ + public static void maybeSetHrBoolAttr(Element ele, String attrName, Boolean b) { + if (b != null) { + ele.setAttribute(attrName, String.valueOf(b)); + } + } + + /** Create an on-device Long DOM Element with the given attribute name. */ + public static Element createOdLongEle(Document doc, String name, long l) { + var ele = doc.createElement(XmlUtils.OD_TAG_LONG); + ele.setAttribute(XmlUtils.OD_ATTR_NAME, name); + ele.setAttribute(XmlUtils.OD_ATTR_VALUE, String.valueOf(l)); + return ele; + } + + /** Create an on-device Long DOM Element with the given attribute name. */ + public static Element createOdStringEle(Document doc, String name, String val) { + var ele = doc.createElement(XmlUtils.OD_TAG_STRING); + ele.setAttribute(XmlUtils.OD_ATTR_NAME, name); + ele.setAttribute(XmlUtils.OD_ATTR_VALUE, val); + return ele; + } + + /** Create OD style array DOM Element, which can represent any time but is stored as Strings. */ + public static Element createOdArray( + Document doc, String arrayTag, String arrayName, List<String> arrayVals) { + Element arrEle = doc.createElement(arrayTag); + arrEle.setAttribute(XmlUtils.OD_ATTR_NAME, arrayName); + arrEle.setAttribute(XmlUtils.OD_ATTR_NUM, String.valueOf(arrayVals.size())); + for (String s : arrayVals) { + Element itemEle = doc.createElement(XmlUtils.OD_TAG_ITEM); + itemEle.setAttribute(XmlUtils.OD_ATTR_VALUE, s); + arrEle.appendChild(itemEle); + } + return arrEle; + } + + /** Returns whether the String is null or empty. */ + public static boolean isNullOrEmpty(String s) { + return s == null || s.isEmpty(); + } + + /** Tries getting required version attribute and throws exception if it doesn't exist */ + public static Long tryGetVersion(Element ele) throws MalformedXmlException { + long version; + try { + version = Long.parseLong(ele.getAttribute(XmlUtils.HR_ATTR_VERSION)); + } catch (Exception e) { + throw new MalformedXmlException( + String.format( + "Malformed or missing required version in: %s", ele.getTagName())); + } + return version; + } + + /** Gets a pipeline-split attribute. */ + public static List<String> getPipelineSplitAttr(Element ele, String attrName, boolean required) + throws MalformedXmlException { + List<String> list = Arrays.stream(ele.getAttribute(attrName).split("\\|")).toList(); + if ((list.isEmpty() || list.get(0).isEmpty()) && required) { + throw new MalformedXmlException( + String.format( + "Delimited string %s was required but missing, in %s.", + attrName, ele.getTagName())); + } + return list; + } + + /** Gets a Boolean attribute. */ + public static Boolean getBoolAttr(Element ele, String attrName, boolean required) + throws MalformedXmlException { + Boolean b = XmlUtils.fromString(ele.getAttribute(attrName)); + if (b == null && required) { + throw new MalformedXmlException( + String.format( + "Boolean %s was required but missing, in %s.", + attrName, ele.getTagName())); + } + return b; + } + + /** Gets a Boolean attribute. */ + public static Boolean getOdBoolEle(Element ele, String nameName, boolean required) + throws MalformedXmlException { + List<Element> boolEles = + XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_BOOLEAN).stream() + .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName)) + .toList(); + if (boolEles.size() > 1) { + throw new MalformedXmlException( + String.format( + "Found more than one boolean %s in %s.", nameName, ele.getTagName())); + } + if (boolEles.isEmpty()) { + if (required) { + throw new MalformedXmlException( + String.format("Found no boolean %s in %s.", nameName, ele.getTagName())); + } + return null; + } + Element boolEle = boolEles.get(0); + + Boolean b = XmlUtils.fromString(boolEle.getAttribute(XmlUtils.OD_ATTR_VALUE)); + if (b == null && required) { + throw new MalformedXmlException( + String.format( + "Boolean %s was required but missing, in %s.", + nameName, ele.getTagName())); + } + return b; + } + + /** Gets an on-device Long attribute. */ + public static Long getOdLongEle(Element ele, String nameName, boolean required) + throws MalformedXmlException { + List<Element> longEles = + XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_LONG).stream() + .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName)) + .toList(); + if (longEles.size() > 1) { + throw new MalformedXmlException( + String.format( + "Found more than one long %s in %s.", nameName, ele.getTagName())); + } + if (longEles.isEmpty()) { + if (required) { + throw new MalformedXmlException( + String.format("Found no long %s in %s.", nameName, ele.getTagName())); + } + return null; + } + Element longEle = longEles.get(0); + Long l = null; + try { + l = Long.parseLong(longEle.getAttribute(XmlUtils.OD_ATTR_VALUE)); + } catch (NumberFormatException e) { + throw new MalformedXmlException( + String.format( + "%s in %s was not formatted as long", nameName, ele.getTagName())); + } + return l; + } + + /** Gets an on-device String attribute. */ + public static String getOdStringEle(Element ele, String nameName, boolean required) + throws MalformedXmlException { + List<Element> eles = + XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_STRING).stream() + .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName)) + .toList(); + if (eles.size() > 1) { + throw new MalformedXmlException( + String.format( + "Found more than one string %s in %s.", nameName, ele.getTagName())); + } + if (eles.isEmpty()) { + if (required) { + throw new MalformedXmlException( + String.format("Found no string %s in %s.", nameName, ele.getTagName())); + } + return null; + } + String str = eles.get(0).getAttribute(XmlUtils.OD_ATTR_VALUE); + if (XmlUtils.isNullOrEmpty(str) && required) { + throw new MalformedXmlException( + String.format( + "%s in %s was empty or missing value", nameName, ele.getTagName())); + } + return str; + } + + /** Gets a OD Pbundle Element attribute with the specified name. */ + public static Element getOdPbundleWithName(Element ele, String nameName, boolean required) + throws MalformedXmlException { + List<Element> eles = + XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_PBUNDLE_AS_MAP).stream() + .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName)) + .toList(); + if (eles.size() > 1) { + throw new MalformedXmlException( + String.format( + "Found more than one pbundle %s in %s.", nameName, ele.getTagName())); + } + if (eles.isEmpty()) { + if (required) { + throw new MalformedXmlException( + String.format("Found no pbundle %s in %s.", nameName, ele.getTagName())); + } + return null; + } + return eles.get(0); + } + + /** Gets a required String attribute. */ + public static String getStringAttr(Element ele, String attrName) throws MalformedXmlException { + return getStringAttr(ele, attrName, true); + } + + /** Gets a String attribute; throws exception if required and non-existent. */ + public static String getStringAttr(Element ele, String attrName, boolean required) + throws MalformedXmlException { + String s = ele.getAttribute(attrName); + if (isNullOrEmpty(s)) { + if (required) { + throw new MalformedXmlException( + String.format( + "Malformed or missing required %s in: %s", + attrName, ele.getTagName())); + } else { + return null; + } + } + return s; + } + + /** Gets on-device style int array. */ + public static List<Integer> getOdIntArray(Element ele, String nameName, boolean required) + throws MalformedXmlException { + List<Element> intArrayEles = + XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_INT_ARRAY).stream() + .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName)) + .toList(); + if (intArrayEles.size() > 1) { + throw new MalformedXmlException( + String.format("Found more than one %s in %s.", nameName, ele.getTagName())); + } + if (intArrayEles.isEmpty()) { + if (required) { + throw new MalformedXmlException( + String.format("Found no %s in %s.", nameName, ele.getTagName())); + } + return null; + } + Element intArrayEle = intArrayEles.get(0); + List<Element> itemEles = XmlUtils.getChildrenByTagName(intArrayEle, XmlUtils.OD_TAG_ITEM); + List<Integer> ints = new ArrayList<Integer>(); + for (Element itemEle : itemEles) { + ints.add(Integer.parseInt(XmlUtils.getStringAttr(itemEle, XmlUtils.OD_ATTR_VALUE))); + } + return ints; + } + + /** Gets on-device style String array. */ + public static List<String> getOdStringArray(Element ele, String nameName, boolean required) + throws MalformedXmlException { + List<Element> arrayEles = + XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_STRING_ARRAY).stream() + .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName)) + .toList(); + if (arrayEles.size() > 1) { + throw new MalformedXmlException( + String.format( + "Found more than one string array %s in %s.", + nameName, ele.getTagName())); + } + if (arrayEles.isEmpty()) { + if (required) { + throw new MalformedXmlException( + String.format( + "Found no string array %s in %s.", nameName, ele.getTagName())); + } + return null; + } + Element arrayEle = arrayEles.get(0); + List<Element> itemEles = XmlUtils.getChildrenByTagName(arrayEle, XmlUtils.OD_TAG_ITEM); + List<String> strs = new ArrayList<String>(); + for (Element itemEle : itemEles) { + strs.add(XmlUtils.getStringAttr(itemEle, XmlUtils.OD_ATTR_VALUE, true)); + } + return strs; + } + + /** + * Utility method for making a List from one element, to support easier refactoring if needed. + * For example, List.of() doesn't support null elements. + */ + public static List<Element> listOf(Element e) { + return Arrays.asList(e); + } +} diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/AllTests.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/AllTests.java new file mode 100644 index 000000000000..dbeeb496144a --- /dev/null +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/AllTests.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2017 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.asllib; + +import com.android.asllib.marshallable.AndroidSafetyLabelTest; +import com.android.asllib.marshallable.AppInfoTest; +import com.android.asllib.marshallable.DataLabelsTest; +import com.android.asllib.marshallable.DataTypeEqualityTest; +import com.android.asllib.marshallable.DeveloperInfoTest; +import com.android.asllib.marshallable.SafetyLabelsTest; +import com.android.asllib.marshallable.SecurityLabelsTest; +import com.android.asllib.marshallable.SystemAppSafetyLabelTest; +import com.android.asllib.marshallable.ThirdPartyVerificationTest; +import com.android.asllib.marshallable.TransparencyInfoTest; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +@RunWith(Suite.class) +@Suite.SuiteClasses({ + AslgenTests.class, + AndroidSafetyLabelTest.class, + AppInfoTest.class, + // DataCategoryTest.class, + DataLabelsTest.class, + DataTypeEqualityTest.class, + DeveloperInfoTest.class, + SafetyLabelsTest.class, + SecurityLabelsTest.class, + SystemAppSafetyLabelTest.class, + ThirdPartyVerificationTest.class, + TransparencyInfoTest.class +}) +public class AllTests {} diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java new file mode 100644 index 000000000000..5d1d45a9a29b --- /dev/null +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2017 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.asllib; + +import static org.junit.Assert.assertEquals; + +import com.android.asllib.marshallable.AndroidSafetyLabel; +import com.android.asllib.testutils.TestUtils; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +@RunWith(JUnit4.class) +public class AslgenTests { + private static final String VALID_MAPPINGS_PATH = "com/android/asllib/validmappings"; + private static final List<String> VALID_MAPPINGS_SUBDIRS = List.of("general"); + private static final String HR_XML_FILENAME = "hr.xml"; + private static final String OD_XML_FILENAME = "od.xml"; + + /** Logic for setting up tests (empty if not yet needed). */ + public static void main(String[] params) throws Exception {} + + /** Tests valid mappings between HR and OD. */ + @Test + public void testValidMappings() throws Exception { + System.out.println("start testing valid mappings."); + + for (String subdir : VALID_MAPPINGS_SUBDIRS) { + Path hrPath = Paths.get(VALID_MAPPINGS_PATH, subdir, HR_XML_FILENAME); + Path odPath = Paths.get(VALID_MAPPINGS_PATH, subdir, OD_XML_FILENAME); + + System.out.println("hr path: " + hrPath.toString()); + System.out.println("od path: " + odPath.toString()); + + InputStream hrStream = + getClass().getClassLoader().getResourceAsStream(hrPath.toString()); + String hrContents = + TestUtils.getFormattedXml( + new String(hrStream.readAllBytes(), StandardCharsets.UTF_8), false); + InputStream odStream = + getClass().getClassLoader().getResourceAsStream(odPath.toString()); + String odContents = + TestUtils.getFormattedXml( + new String(odStream.readAllBytes(), StandardCharsets.UTF_8), false); + AndroidSafetyLabel aslFromHr = + AslConverter.readFromString(hrContents, AslConverter.Format.HUMAN_READABLE); + String aslToOdStr = + TestUtils.getFormattedXml( + AslConverter.getXmlAsString(aslFromHr, AslConverter.Format.ON_DEVICE), + false); + AndroidSafetyLabel aslFromOd = + AslConverter.readFromString(odContents, AslConverter.Format.ON_DEVICE); + String aslToHrStr = + TestUtils.getFormattedXml( + AslConverter.getXmlAsString( + aslFromOd, AslConverter.Format.HUMAN_READABLE), + false); + + System.out.println("od expected: " + odContents); + System.out.println("asl to od: " + aslToOdStr); + assertEquals(odContents, aslToOdStr); + + System.out.println("hr expected: " + hrContents); + System.out.println("asl to hr: " + aslToHrStr); + assertEquals(hrContents, aslToHrStr); + } + } +} diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AndroidSafetyLabelTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AndroidSafetyLabelTest.java new file mode 100644 index 000000000000..61a78232801c --- /dev/null +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AndroidSafetyLabelTest.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2017 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.asllib.marshallable; + +import com.android.asllib.testutils.TestUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class AndroidSafetyLabelTest { + private static final String ANDROID_SAFETY_LABEL_HR_PATH = + "com/android/asllib/androidsafetylabel/hr"; + private static final String ANDROID_SAFETY_LABEL_OD_PATH = + "com/android/asllib/androidsafetylabel/od"; + + private static final String MISSING_VERSION_FILE_NAME = "missing-version.xml"; + private static final String VALID_EMPTY_FILE_NAME = "valid-empty.xml"; + private static final String WITH_SAFETY_LABELS_FILE_NAME = "with-safety-labels.xml"; + private static final String WITH_SYSTEM_APP_SAFETY_LABEL_FILE_NAME = + "with-system-app-safety-label.xml"; + private static final String WITH_TRANSPARENCY_INFO_FILE_NAME = "with-transparency-info.xml"; + + @Before + public void setUp() throws Exception { + System.out.println("set up."); + } + + /** Test for android safety label missing version. */ + @Test + public void testAndroidSafetyLabelMissingVersion() throws Exception { + System.out.println("starting testAndroidSafetyLabelMissingVersion."); + hrToOdExpectException(MISSING_VERSION_FILE_NAME); + odToHrExpectException(MISSING_VERSION_FILE_NAME); + } + + /** Test for android safety label valid empty. */ + @Test + public void testAndroidSafetyLabelValidEmptyFile() throws Exception { + System.out.println("starting testAndroidSafetyLabelValidEmptyFile."); + testHrToOdAndroidSafetyLabel(VALID_EMPTY_FILE_NAME); + testOdToHrAndroidSafetyLabel(VALID_EMPTY_FILE_NAME); + } + + /** Test for android safety label with safety labels. */ + @Test + public void testAndroidSafetyLabelWithSafetyLabels() throws Exception { + System.out.println("starting testAndroidSafetyLabelWithSafetyLabels."); + testHrToOdAndroidSafetyLabel(WITH_SAFETY_LABELS_FILE_NAME); + testOdToHrAndroidSafetyLabel(WITH_SAFETY_LABELS_FILE_NAME); + } + + /** Test for android safety label with system app safety label. */ + @Test + public void testAndroidSafetyLabelWithSystemAppSafetyLabel() throws Exception { + System.out.println("starting testAndroidSafetyLabelWithSystemAppSafetyLabel."); + testHrToOdAndroidSafetyLabel(WITH_SYSTEM_APP_SAFETY_LABEL_FILE_NAME); + testOdToHrAndroidSafetyLabel(WITH_SYSTEM_APP_SAFETY_LABEL_FILE_NAME); + } + + /** Test for android safety label with transparency info. */ + @Test + public void testAndroidSafetyLabelWithTransparencyInfo() throws Exception { + System.out.println("starting testAndroidSafetyLabelWithTransparencyInfo."); + testHrToOdAndroidSafetyLabel(WITH_TRANSPARENCY_INFO_FILE_NAME); + testOdToHrAndroidSafetyLabel(WITH_TRANSPARENCY_INFO_FILE_NAME); + } + + private void hrToOdExpectException(String fileName) { + TestUtils.hrToOdExpectException( + new AndroidSafetyLabelFactory(), ANDROID_SAFETY_LABEL_HR_PATH, fileName); + } + + private void odToHrExpectException(String fileName) { + TestUtils.odToHrExpectException( + new AndroidSafetyLabelFactory(), ANDROID_SAFETY_LABEL_OD_PATH, fileName); + } + + private void testHrToOdAndroidSafetyLabel(String fileName) throws Exception { + TestUtils.testHrToOd( + TestUtils.document(), + new AndroidSafetyLabelFactory(), + ANDROID_SAFETY_LABEL_HR_PATH, + ANDROID_SAFETY_LABEL_OD_PATH, + fileName); + } + + private void testOdToHrAndroidSafetyLabel(String fileName) throws Exception { + TestUtils.testOdToHr( + TestUtils.document(), + new AndroidSafetyLabelFactory(), + ANDROID_SAFETY_LABEL_OD_PATH, + ANDROID_SAFETY_LABEL_HR_PATH, + fileName); + } +} diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java new file mode 100644 index 000000000000..9e91c6f22641 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2017 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.asllib.marshallable; + +import static org.junit.Assert.assertThrows; + +import com.android.asllib.testutils.TestUtils; +import com.android.asllib.util.MalformedXmlException; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.nio.file.Paths; +import java.util.List; + +@RunWith(JUnit4.class) +public class AppInfoTest { + private static final String APP_INFO_HR_PATH = "com/android/asllib/appinfo/hr"; + private static final String APP_INFO_OD_PATH = "com/android/asllib/appinfo/od"; + public static final List<String> REQUIRED_FIELD_NAMES = + List.of( + "title", + "description", + "containsAds", + "obeyAps", + "adsFingerprinting", + "securityFingerprinting", + "privacyPolicy", + "securityEndpoints", + "firstPartyEndpoints", + "serviceProviderEndpoints", + "category", + "email"); + public static final List<String> REQUIRED_FIELD_NAMES_OD = + List.of( + "title", + "description", + "contains_ads", + "obey_aps", + "ads_fingerprinting", + "security_fingerprinting", + "privacy_policy", + "security_endpoint", + "first_party_endpoint", + "service_provider_endpoint", + "category", + "email"); + public static final List<String> OPTIONAL_FIELD_NAMES = List.of("website"); + public static final List<String> OPTIONAL_FIELD_NAMES_OD = List.of("website"); + + private static final String ALL_FIELDS_VALID_FILE_NAME = "all-fields-valid.xml"; + + /** Logic for setting up tests (empty if not yet needed). */ + public static void main(String[] params) throws Exception {} + + @Before + public void setUp() throws Exception { + System.out.println("set up."); + } + + /** Test for all fields valid. */ + @Test + public void testAllFieldsValid() throws Exception { + System.out.println("starting testAllFieldsValid."); + testHrToOdAppInfo(ALL_FIELDS_VALID_FILE_NAME); + testOdToHrAppInfo(ALL_FIELDS_VALID_FILE_NAME); + } + + /** Tests missing required fields fails. */ + @Test + public void testMissingRequiredFields() throws Exception { + System.out.println("Starting testMissingRequiredFields"); + for (String reqField : REQUIRED_FIELD_NAMES) { + System.out.println("testing missing required field hr: " + reqField); + var appInfoEle = + TestUtils.getElementsFromResource( + Paths.get(APP_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME)); + appInfoEle.get(0).removeAttribute(reqField); + + assertThrows( + MalformedXmlException.class, + () -> new AppInfoFactory().createFromHrElements(appInfoEle)); + } + + for (String reqField : REQUIRED_FIELD_NAMES_OD) { + System.out.println("testing missing required field od: " + reqField); + var appInfoEle = + TestUtils.getElementsFromResource( + Paths.get(APP_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME)); + TestUtils.removeOdChildEleWithName(appInfoEle.get(0), reqField); + assertThrows( + MalformedXmlException.class, + () -> new AppInfoFactory().createFromOdElements(appInfoEle)); + } + } + + /** Tests missing optional fields passes. */ + @Test + public void testMissingOptionalFields() throws Exception { + for (String optField : OPTIONAL_FIELD_NAMES) { + var ele = + TestUtils.getElementsFromResource( + Paths.get(APP_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME)); + ele.get(0).removeAttribute(optField); + AppInfo appInfo = new AppInfoFactory().createFromHrElements(ele); + appInfo.toOdDomElements(TestUtils.document()); + } + + for (String optField : OPTIONAL_FIELD_NAMES_OD) { + var ele = + TestUtils.getElementsFromResource( + Paths.get(APP_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME)); + TestUtils.removeOdChildEleWithName(ele.get(0), optField); + AppInfo appInfo = new AppInfoFactory().createFromOdElements(ele); + appInfo.toHrDomElements(TestUtils.document()); + } + } + + private void testHrToOdAppInfo(String fileName) throws Exception { + TestUtils.testHrToOd( + TestUtils.document(), + new AppInfoFactory(), + APP_INFO_HR_PATH, + APP_INFO_OD_PATH, + fileName); + } + + private void testOdToHrAppInfo(String fileName) throws Exception { + TestUtils.testOdToHr( + TestUtils.document(), + new AppInfoFactory(), + APP_INFO_OD_PATH, + APP_INFO_HR_PATH, + fileName); + } +} diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java new file mode 100644 index 000000000000..ff4374166dd3 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2017 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.asllib.marshallable; + +import com.android.asllib.testutils.TestUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class DataLabelsTest { + private static final String DATA_LABELS_HR_PATH = "com/android/asllib/datalabels/hr"; + private static final String DATA_LABELS_OD_PATH = "com/android/asllib/datalabels/od"; + + private static final String ACCESSED_VALID_BOOL_FILE_NAME = + "data-labels-accessed-valid-bool.xml"; + private static final String ACCESSED_INVALID_BOOL_FILE_NAME = + "data-labels-accessed-invalid-bool.xml"; + private static final String COLLECTED_VALID_BOOL_FILE_NAME = + "data-labels-collected-valid-bool.xml"; + private static final String COLLECTED_EPHEMERAL_FILE_NAME = + "data-labels-collected-ephemeral.xml"; + private static final String COLLECTED_EPHEMERAL_COLLISION_FILE_NAME = + "data-labels-collected-ephemeral-collision.xml"; + private static final String COLLECTED_INVALID_BOOL_FILE_NAME = + "data-labels-collected-invalid-bool.xml"; + private static final String SHARED_VALID_BOOL_FILE_NAME = "data-labels-shared-valid-bool.xml"; + private static final String SHARED_INVALID_BOOL_FILE_NAME = + "data-labels-shared-invalid-bool.xml"; + + private static final String ACTIONS_IN_APP_FILE_NAME = "data-category-actions-in-app.xml"; + private static final String APP_PERFORMANCE_FILE_NAME = "data-category-app-performance.xml"; + private static final String AUDIO_FILE_NAME = "data-category-audio.xml"; + private static final String CALENDAR_FILE_NAME = "data-category-calendar.xml"; + private static final String CONTACTS_FILE_NAME = "data-category-contacts.xml"; + private static final String EMAIL_TEXT_MESSAGE_FILE_NAME = + "data-category-email-text-message.xml"; + private static final String FINANCIAL_FILE_NAME = "data-category-financial.xml"; + private static final String HEALTH_FITNESS_FILE_NAME = "data-category-health-fitness.xml"; + private static final String IDENTIFIERS_FILE_NAME = "data-category-identifiers.xml"; + private static final String LOCATION_FILE_NAME = "data-category-location.xml"; + private static final String PERSONAL_FILE_NAME = "data-category-personal.xml"; + private static final String PERSONAL_PARTIAL_FILE_NAME = "data-category-personal-partial.xml"; + private static final String PHOTO_VIDEO_FILE_NAME = "data-category-photo-video.xml"; + private static final String SEARCH_AND_BROWSING_FILE_NAME = + "data-category-search-and-browsing.xml"; + private static final String STORAGE_FILE_NAME = "data-category-storage.xml"; + private static final String PERSONAL_MISSING_PURPOSE_FILE_NAME = + "data-category-personal-missing-purpose.xml"; + private static final String PERSONAL_EMPTY_PURPOSE_FILE_NAME = + "data-category-personal-empty-purpose.xml"; + private static final String UNRECOGNIZED_FILE_NAME = "data-category-unrecognized.xml"; + private static final String UNRECOGNIZED_TYPE_FILE_NAME = "data-category-unrecognized-type.xml"; + + @Before + public void setUp() throws Exception { + System.out.println("set up."); + } + + /** Test for data labels collected valid bool. */ + @Test + public void testDataLabelsCollectedValidBool() throws Exception { + System.out.println("starting testDataLabelsCollectedValidBool."); + testHrToOdDataLabels(COLLECTED_VALID_BOOL_FILE_NAME); + testOdToHrDataLabels(COLLECTED_VALID_BOOL_FILE_NAME); + } + + /** Test for data labels collected ephemeral. */ + @Test + public void testDataLabelsCollectedEphemeral() throws Exception { + System.out.println("starting testDataLabelsCollectedEphemeral."); + testHrToOdDataLabels(COLLECTED_EPHEMERAL_FILE_NAME); + testOdToHrDataLabels(COLLECTED_EPHEMERAL_FILE_NAME); + } + + /** Test for data labels ephemeral collision. */ + @Test + public void testDataLabelsCollectedEphemeralCollision() throws Exception { + System.out.println("starting testDataLabelsCollectedEphemeralCollision."); + hrToOdExpectException(COLLECTED_EPHEMERAL_COLLISION_FILE_NAME); + } + + /** Test for data labels collected invalid bool. */ + @Test + public void testDataLabelsCollectedInvalidBool() throws Exception { + System.out.println("starting testDataLabelsCollectedInvalidBool."); + hrToOdExpectException(COLLECTED_INVALID_BOOL_FILE_NAME); + odToHrExpectException(COLLECTED_INVALID_BOOL_FILE_NAME); + } + + /** Test for data labels shared valid bool. */ + @Test + public void testDataLabelsSharedValidBool() throws Exception { + System.out.println("starting testDataLabelsSharedValidBool."); + testHrToOdDataLabels(SHARED_VALID_BOOL_FILE_NAME); + testOdToHrDataLabels(SHARED_VALID_BOOL_FILE_NAME); + } + + /** Test for data labels shared invalid bool. */ + @Test + public void testDataLabelsSharedInvalidBool() throws Exception { + System.out.println("starting testDataLabelsSharedInvalidBool."); + hrToOdExpectException(SHARED_INVALID_BOOL_FILE_NAME); + } + + /* Data categories bidirectional tests... */ + + /** Test for data labels actions in app. */ + @Test + public void testDataLabelsActionsInApp() throws Exception { + System.out.println("starting testDataLabelsActionsInApp."); + testHrToOdDataLabels(ACTIONS_IN_APP_FILE_NAME); + testOdToHrDataLabels(ACTIONS_IN_APP_FILE_NAME); + } + + /** Test for data labels app performance. */ + @Test + public void testDataLabelsAppPerformance() throws Exception { + System.out.println("starting testDataLabelsAppPerformance."); + testHrToOdDataLabels(APP_PERFORMANCE_FILE_NAME); + testOdToHrDataLabels(APP_PERFORMANCE_FILE_NAME); + } + + /** Test for data labels audio. */ + @Test + public void testDataLabelsAudio() throws Exception { + System.out.println("starting testDataLabelsAudio."); + testHrToOdDataLabels(AUDIO_FILE_NAME); + testOdToHrDataLabels(AUDIO_FILE_NAME); + } + + /** Test for data labels calendar. */ + @Test + public void testDataLabelsCalendar() throws Exception { + System.out.println("starting testDataLabelsCalendar."); + testHrToOdDataLabels(CALENDAR_FILE_NAME); + testOdToHrDataLabels(CALENDAR_FILE_NAME); + } + + /** Test for data labels contacts. */ + @Test + public void testDataLabelsContacts() throws Exception { + System.out.println("starting testDataLabelsContacts."); + testHrToOdDataLabels(CONTACTS_FILE_NAME); + testOdToHrDataLabels(CONTACTS_FILE_NAME); + } + + /** Test for data labels email text message. */ + @Test + public void testDataLabelsEmailTextMessage() throws Exception { + System.out.println("starting testDataLabelsEmailTextMessage."); + testHrToOdDataLabels(EMAIL_TEXT_MESSAGE_FILE_NAME); + testOdToHrDataLabels(EMAIL_TEXT_MESSAGE_FILE_NAME); + } + + /** Test for data labels financial. */ + @Test + public void testDataLabelsFinancial() throws Exception { + System.out.println("starting testDataLabelsFinancial."); + testHrToOdDataLabels(FINANCIAL_FILE_NAME); + testOdToHrDataLabels(FINANCIAL_FILE_NAME); + } + + /** Test for data labels health fitness. */ + @Test + public void testDataLabelsHealthFitness() throws Exception { + System.out.println("starting testDataLabelsHealthFitness."); + testHrToOdDataLabels(HEALTH_FITNESS_FILE_NAME); + testOdToHrDataLabels(HEALTH_FITNESS_FILE_NAME); + } + + /** Test for data labels identifiers. */ + @Test + public void testDataLabelsIdentifiers() throws Exception { + System.out.println("starting testDataLabelsIdentifiers."); + testHrToOdDataLabels(IDENTIFIERS_FILE_NAME); + testOdToHrDataLabels(IDENTIFIERS_FILE_NAME); + } + + /** Test for data labels location. */ + @Test + public void testDataLabelsLocation() throws Exception { + System.out.println("starting testDataLabelsLocation."); + testHrToOdDataLabels(LOCATION_FILE_NAME); + testOdToHrDataLabels(LOCATION_FILE_NAME); + } + + /** Test for data labels personal. */ + @Test + public void testDataLabelsPersonal() throws Exception { + System.out.println("starting testDataLabelsPersonal."); + testHrToOdDataLabels(PERSONAL_FILE_NAME); + testOdToHrDataLabels(PERSONAL_FILE_NAME); + } + + /** Test for data labels personal partial. */ + @Test + public void testDataLabelsPersonalPartial() throws Exception { + System.out.println("starting testDataLabelsPersonalPartial."); + testHrToOdDataLabels(PERSONAL_PARTIAL_FILE_NAME); + testOdToHrDataLabels(PERSONAL_PARTIAL_FILE_NAME); + } + + /** Test for data labels photo video. */ + @Test + public void testDataLabelsPhotoVideo() throws Exception { + System.out.println("starting testDataLabelsPhotoVideo."); + testHrToOdDataLabels(PHOTO_VIDEO_FILE_NAME); + testOdToHrDataLabels(PHOTO_VIDEO_FILE_NAME); + } + + /** Test for data labels search and browsing. */ + @Test + public void testDataLabelsSearchAndBrowsing() throws Exception { + System.out.println("starting testDataLabelsSearchAndBrowsing."); + testHrToOdDataLabels(SEARCH_AND_BROWSING_FILE_NAME); + testOdToHrDataLabels(SEARCH_AND_BROWSING_FILE_NAME); + } + + /** Test for data labels storage. */ + @Test + public void testDataLabelsStorage() throws Exception { + System.out.println("starting testDataLabelsStorage."); + testHrToOdDataLabels(STORAGE_FILE_NAME); + testOdToHrDataLabels(STORAGE_FILE_NAME); + } + + /** Test for data labels hr unrecognized data category. */ + @Test + public void testDataLabelsHrUnrecognizedDataCategory() throws Exception { + System.out.println("starting testDataLabelsHrUnrecognizedDataCategory."); + hrToOdExpectException(UNRECOGNIZED_FILE_NAME); + } + + /** Test for data labels hr unrecognized data type. */ + @Test + public void testDataLabelsHrUnrecognizedDataType() throws Exception { + System.out.println("starting testDataLabelsHrUnrecognizedDataType."); + hrToOdExpectException(UNRECOGNIZED_TYPE_FILE_NAME); + } + + /** Test for data labels hr missing purpose. */ + @Test + public void testDataLabelsHrMissingPurpose() throws Exception { + System.out.println("starting testDataLabelsHrMissingPurpose."); + hrToOdExpectException(PERSONAL_MISSING_PURPOSE_FILE_NAME); + } + + /** Test for data labels hr empty purpose. */ + @Test + public void testDataLabelsHrEmptyPurpose() throws Exception { + System.out.println("starting testDataLabelsHrEmptyPurpose."); + hrToOdExpectException(PERSONAL_EMPTY_PURPOSE_FILE_NAME); + } + + /** Test for data labels od unrecognized data category. */ + @Test + public void testDataLabelsOdUnrecognizedDataCategory() throws Exception { + System.out.println("starting testDataLabelsOdUnrecognizedDataCategory."); + odToHrExpectException(UNRECOGNIZED_FILE_NAME); + } + + /** Test for data labels od unrecognized data type. */ + @Test + public void testDataLabelsOdUnrecognizedDataType() throws Exception { + System.out.println("starting testDataLabelsOdUnrecognizedDataCategory."); + odToHrExpectException(UNRECOGNIZED_TYPE_FILE_NAME); + } + + /** Test for data labels od missing purpose. */ + @Test + public void testDataLabelsOdMissingPurpose() throws Exception { + System.out.println("starting testDataLabelsOdMissingPurpose."); + odToHrExpectException(PERSONAL_MISSING_PURPOSE_FILE_NAME); + } + + /** Test for data labels od empty purpose. */ + @Test + public void testDataLabelsOdEmptyPurpose() throws Exception { + System.out.println("starting testDataLabelsOdEmptyPurpose."); + odToHrExpectException(PERSONAL_EMPTY_PURPOSE_FILE_NAME); + } + + private void hrToOdExpectException(String fileName) { + TestUtils.hrToOdExpectException(new DataLabelsFactory(), DATA_LABELS_HR_PATH, fileName); + } + + private void odToHrExpectException(String fileName) { + TestUtils.odToHrExpectException(new DataLabelsFactory(), DATA_LABELS_OD_PATH, fileName); + } + + private void testHrToOdDataLabels(String fileName) throws Exception { + TestUtils.testHrToOd( + TestUtils.document(), + new DataLabelsFactory(), + DATA_LABELS_HR_PATH, + DATA_LABELS_OD_PATH, + fileName); + } + + private void testOdToHrDataLabels(String fileName) throws Exception { + TestUtils.testOdToHr( + TestUtils.document(), + new DataLabelsFactory(), + DATA_LABELS_OD_PATH, + DATA_LABELS_HR_PATH, + fileName); + } +} diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataTypeEqualityTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataTypeEqualityTest.java new file mode 100644 index 000000000000..da7f2879720e --- /dev/null +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataTypeEqualityTest.java @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2017 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.asllib.marshallable; + +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 org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@RunWith(JUnit4.class) +public class DataTypeEqualityTest { + + public static final List<String> OPTIONAL_FIELD_NAMES = + List.of("isDataDeletable", "isDataEncrypted"); + public static final List<String> OPTIONAL_FIELD_NAMES_OD = + List.of("is_data_deletable", "is_data_encrypted"); + + /** Logic for setting up tests (empty if not yet needed). */ + public static void main(String[] params) throws Exception {} + + @Before + public void setUp() throws Exception { + System.out.println("set up."); + } + + /** Test for equality different order. */ + @Test + public void testEqualityDifferentOrder() throws Exception { + System.out.println("starting testEqualityDifferentOrder."); + DataType dataType1 = + new DataType( + "datatype1", + Arrays.asList( + DataType.Purpose.ADVERTISING, DataType.Purpose.PERSONALIZATION), + true, + false, + null); + DataType dataType2 = + new DataType( + "datatype1", + Arrays.asList( + DataType.Purpose.PERSONALIZATION, DataType.Purpose.ADVERTISING), + true, + false, + null); + assertEquals(dataType1, dataType2); + assertEquals(dataType2, dataType1); + } + + /** Test for contains different order. */ + @Test + public void testContainsDifferentOrder() throws Exception { + System.out.println("starting testContainsDifferentOrder."); + DataType dataType1 = + new DataType( + "datatype1", + Arrays.asList( + DataType.Purpose.ADVERTISING, DataType.Purpose.PERSONALIZATION), + true, + false, + null); + DataType dataType2 = + new DataType( + "datatype1", + Arrays.asList( + DataType.Purpose.PERSONALIZATION, DataType.Purpose.ADVERTISING), + true, + false, + null); + Set<DataType> set = new HashSet<>(); + set.add(dataType1); + assertTrue(set.contains(dataType2)); + } + + /** Test for inequality. */ + @Test + public void testInequality() throws Exception { + System.out.println("starting testInequality."); + DataType dataType1 = + new DataType( + "datatype1", + Arrays.asList( + DataType.Purpose.ADVERTISING, DataType.Purpose.PERSONALIZATION), + true, + false, + null); + DataType dataType2 = + new DataType( + "datatype1", + Arrays.asList(DataType.Purpose.PERSONALIZATION), + true, + false, + null); + assertNotEquals(dataType1, dataType2); + assertNotEquals(dataType2, dataType1); + } + + /** Test for inequality bool. */ + @Test + public void testInequalityBool() throws Exception { + System.out.println("starting testInequalityBool."); + DataType dataType1 = + new DataType( + "datatype1", + Arrays.asList( + DataType.Purpose.ADVERTISING, DataType.Purpose.PERSONALIZATION), + true, + false, + null); + DataType dataType2 = + new DataType( + "datatype1", + Arrays.asList( + DataType.Purpose.ADVERTISING, DataType.Purpose.PERSONALIZATION), + true, + false, + true); + assertNotEquals(dataType1, dataType2); + assertNotEquals(dataType2, dataType1); + } + + /** Test for does not contain. */ + @Test + public void testDoesNotContain() throws Exception { + System.out.println("starting testDoesNotContain."); + System.out.println("starting testContainsDifferentOrder."); + DataType dataType1 = + new DataType( + "datatype1", + Arrays.asList( + DataType.Purpose.ADVERTISING, DataType.Purpose.PERSONALIZATION), + true, + false, + null); + DataType dataType2 = + new DataType( + "datatype1", + Arrays.asList(DataType.Purpose.PERSONALIZATION), + true, + false, + null); + Set<DataType> set = new HashSet<>(); + set.add(dataType1); + assertFalse(set.contains(dataType2)); + } +} diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DeveloperInfoTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DeveloperInfoTest.java new file mode 100644 index 000000000000..72e8d654b542 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DeveloperInfoTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2017 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.asllib.marshallable; + +import static org.junit.Assert.assertThrows; + +import com.android.asllib.testutils.TestUtils; +import com.android.asllib.util.MalformedXmlException; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.nio.file.Paths; +import java.util.List; + +@RunWith(JUnit4.class) +public class DeveloperInfoTest { + private static final String DEVELOPER_INFO_HR_PATH = "com/android/asllib/developerinfo/hr"; + private static final String DEVELOPER_INFO_OD_PATH = "com/android/asllib/developerinfo/od"; + public static final List<String> REQUIRED_FIELD_NAMES = + List.of("address", "countryRegion", "email", "name", "relationship"); + public static final List<String> REQUIRED_FIELD_NAMES_OD = + List.of("address", "country_region", "email", "name", "relationship"); + public static final List<String> OPTIONAL_FIELD_NAMES = List.of("website", "registryId"); + public static final List<String> OPTIONAL_FIELD_NAMES_OD = + List.of("website", "app_developer_registry_id"); + + private static final String ALL_FIELDS_VALID_FILE_NAME = "all-fields-valid.xml"; + + /** Logic for setting up tests (empty if not yet needed). */ + public static void main(String[] params) throws Exception {} + + @Before + public void setUp() throws Exception { + System.out.println("set up."); + } + + /** Test for all fields valid. */ + @Test + public void testAllFieldsValid() throws Exception { + System.out.println("starting testAllFieldsValid."); + testHrToOdDeveloperInfo(ALL_FIELDS_VALID_FILE_NAME); + testOdToHrDeveloperInfo(ALL_FIELDS_VALID_FILE_NAME); + } + + /** Tests missing required fields fails. */ + @Test + public void testMissingRequiredFields() throws Exception { + System.out.println("Starting testMissingRequiredFields"); + for (String reqField : REQUIRED_FIELD_NAMES) { + System.out.println("testing missing required field: " + reqField); + var developerInfoEle = + TestUtils.getElementsFromResource( + Paths.get(DEVELOPER_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME)); + developerInfoEle.get(0).removeAttribute(reqField); + + assertThrows( + MalformedXmlException.class, + () -> new DeveloperInfoFactory().createFromHrElements(developerInfoEle)); + } + + for (String reqField : REQUIRED_FIELD_NAMES_OD) { + System.out.println("testing missing required field od: " + reqField); + var developerInfoEle = + TestUtils.getElementsFromResource( + Paths.get(DEVELOPER_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME)); + TestUtils.removeOdChildEleWithName(developerInfoEle.get(0), reqField); + + assertThrows( + MalformedXmlException.class, + () -> new DeveloperInfoFactory().createFromOdElements(developerInfoEle)); + } + } + + /** Tests missing optional fields passes. */ + @Test + public void testMissingOptionalFields() throws Exception { + for (String optField : OPTIONAL_FIELD_NAMES) { + var developerInfoEle = + TestUtils.getElementsFromResource( + Paths.get(DEVELOPER_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME)); + developerInfoEle.get(0).removeAttribute(optField); + DeveloperInfo developerInfo = + new DeveloperInfoFactory().createFromHrElements(developerInfoEle); + developerInfo.toOdDomElements(TestUtils.document()); + } + + for (String optField : OPTIONAL_FIELD_NAMES_OD) { + var developerInfoEle = + TestUtils.getElementsFromResource( + Paths.get(DEVELOPER_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME)); + TestUtils.removeOdChildEleWithName(developerInfoEle.get(0), optField); + DeveloperInfo developerInfo = + new DeveloperInfoFactory().createFromOdElements(developerInfoEle); + developerInfo.toHrDomElements(TestUtils.document()); + } + } + + private void testHrToOdDeveloperInfo(String fileName) throws Exception { + TestUtils.testHrToOd( + TestUtils.document(), + new DeveloperInfoFactory(), + DEVELOPER_INFO_HR_PATH, + DEVELOPER_INFO_OD_PATH, + fileName); + } + + private void testOdToHrDeveloperInfo(String fileName) throws Exception { + TestUtils.testOdToHr( + TestUtils.document(), + new DeveloperInfoFactory(), + DEVELOPER_INFO_OD_PATH, + DEVELOPER_INFO_HR_PATH, + fileName); + } +} diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java new file mode 100644 index 000000000000..bba6b548beaf --- /dev/null +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2017 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.asllib.marshallable; + +import com.android.asllib.testutils.TestUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class SafetyLabelsTest { + private static final String SAFETY_LABELS_HR_PATH = "com/android/asllib/safetylabels/hr"; + private static final String SAFETY_LABELS_OD_PATH = "com/android/asllib/safetylabels/od"; + + private static final String MISSING_VERSION_FILE_NAME = "missing-version.xml"; + private static final String VALID_EMPTY_FILE_NAME = "valid-empty.xml"; + private static final String WITH_DATA_LABELS_FILE_NAME = "with-data-labels.xml"; + private static final String WITH_SECURITY_LABELS_FILE_NAME = "with-security-labels.xml"; + private static final String WITH_THIRD_PARTY_VERIFICATION_FILE_NAME = + "with-third-party-verification.xml"; + + @Before + public void setUp() throws Exception { + System.out.println("set up."); + } + + /** Test for safety labels missing version. */ + @Test + public void testSafetyLabelsMissingVersion() throws Exception { + System.out.println("starting testSafetyLabelsMissingVersion."); + hrToOdExpectException(MISSING_VERSION_FILE_NAME); + odToHrExpectException(MISSING_VERSION_FILE_NAME); + } + + /** Test for safety labels valid empty. */ + @Test + public void testSafetyLabelsValidEmptyFile() throws Exception { + System.out.println("starting testSafetyLabelsValidEmptyFile."); + testHrToOdSafetyLabels(VALID_EMPTY_FILE_NAME); + testOdToHrSafetyLabels(VALID_EMPTY_FILE_NAME); + } + + /** Test for safety labels with data labels. */ + @Test + public void testSafetyLabelsWithDataLabels() throws Exception { + System.out.println("starting testSafetyLabelsWithDataLabels."); + testHrToOdSafetyLabels(WITH_DATA_LABELS_FILE_NAME); + testOdToHrSafetyLabels(WITH_DATA_LABELS_FILE_NAME); + } + + /** Test for safety labels with security labels. */ + @Test + public void testSafetyLabelsWithSecurityLabels() throws Exception { + System.out.println("starting testSafetyLabelsWithSecurityLabels."); + testHrToOdSafetyLabels(WITH_SECURITY_LABELS_FILE_NAME); + testOdToHrSafetyLabels(WITH_SECURITY_LABELS_FILE_NAME); + } + + /** Test for safety labels with third party verification. */ + @Test + public void testSafetyLabelsWithThirdPartyVerification() throws Exception { + System.out.println("starting testSafetyLabelsWithThirdPartyVerification."); + testHrToOdSafetyLabels(WITH_THIRD_PARTY_VERIFICATION_FILE_NAME); + testOdToHrSafetyLabels(WITH_THIRD_PARTY_VERIFICATION_FILE_NAME); + } + + private void hrToOdExpectException(String fileName) { + TestUtils.hrToOdExpectException(new SafetyLabelsFactory(), SAFETY_LABELS_HR_PATH, fileName); + } + + private void odToHrExpectException(String fileName) { + TestUtils.odToHrExpectException(new SafetyLabelsFactory(), SAFETY_LABELS_OD_PATH, fileName); + } + + private void testHrToOdSafetyLabels(String fileName) throws Exception { + TestUtils.testHrToOd( + TestUtils.document(), + new SafetyLabelsFactory(), + SAFETY_LABELS_HR_PATH, + SAFETY_LABELS_OD_PATH, + fileName); + } + + private void testOdToHrSafetyLabels(String fileName) throws Exception { + TestUtils.testOdToHr( + TestUtils.document(), + new SafetyLabelsFactory(), + SAFETY_LABELS_OD_PATH, + SAFETY_LABELS_HR_PATH, + fileName); + } +} diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SecurityLabelsTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SecurityLabelsTest.java new file mode 100644 index 000000000000..a940bc63c685 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SecurityLabelsTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 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.asllib.marshallable; + + +import com.android.asllib.testutils.TestUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.nio.file.Paths; +import java.util.List; + +@RunWith(JUnit4.class) +public class SecurityLabelsTest { + private static final String SECURITY_LABELS_HR_PATH = "com/android/asllib/securitylabels/hr"; + private static final String SECURITY_LABELS_OD_PATH = "com/android/asllib/securitylabels/od"; + + public static final List<String> OPTIONAL_FIELD_NAMES = + List.of("isDataDeletable", "isDataEncrypted"); + public static final List<String> OPTIONAL_FIELD_NAMES_OD = + List.of("is_data_deletable", "is_data_encrypted"); + + private static final String ALL_FIELDS_VALID_FILE_NAME = "all-fields-valid.xml"; + + /** Logic for setting up tests (empty if not yet needed). */ + public static void main(String[] params) throws Exception {} + + @Before + public void setUp() throws Exception { + System.out.println("set up."); + } + + /** Test for all fields valid. */ + @Test + public void testAllFieldsValid() throws Exception { + System.out.println("starting testAllFieldsValid."); + testHrToOdSecurityLabels(ALL_FIELDS_VALID_FILE_NAME); + testOdToHrSecurityLabels(ALL_FIELDS_VALID_FILE_NAME); + } + + /** Tests missing optional fields passes. */ + @Test + public void testMissingOptionalFields() throws Exception { + for (String optField : OPTIONAL_FIELD_NAMES) { + var ele = + TestUtils.getElementsFromResource( + Paths.get(SECURITY_LABELS_HR_PATH, ALL_FIELDS_VALID_FILE_NAME)); + ele.get(0).removeAttribute(optField); + SecurityLabels securityLabels = new SecurityLabelsFactory().createFromHrElements(ele); + securityLabels.toOdDomElements(TestUtils.document()); + } + for (String optField : OPTIONAL_FIELD_NAMES_OD) { + var ele = + TestUtils.getElementsFromResource( + Paths.get(SECURITY_LABELS_OD_PATH, ALL_FIELDS_VALID_FILE_NAME)); + TestUtils.removeOdChildEleWithName(ele.get(0), optField); + SecurityLabels securityLabels = new SecurityLabelsFactory().createFromOdElements(ele); + securityLabels.toHrDomElements(TestUtils.document()); + } + } + + private void testHrToOdSecurityLabels(String fileName) throws Exception { + TestUtils.testHrToOd( + TestUtils.document(), + new SecurityLabelsFactory(), + SECURITY_LABELS_HR_PATH, + SECURITY_LABELS_OD_PATH, + fileName); + } + + private void testOdToHrSecurityLabels(String fileName) throws Exception { + TestUtils.testOdToHr( + TestUtils.document(), + new SecurityLabelsFactory(), + SECURITY_LABELS_OD_PATH, + SECURITY_LABELS_HR_PATH, + fileName); + } +} diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SystemAppSafetyLabelTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SystemAppSafetyLabelTest.java new file mode 100644 index 000000000000..87d3e4499f5c --- /dev/null +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SystemAppSafetyLabelTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2017 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.asllib.marshallable; + +import com.android.asllib.testutils.TestUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class SystemAppSafetyLabelTest { + private static final String SYSTEM_APP_SAFETY_LABEL_HR_PATH = + "com/android/asllib/systemappsafetylabel/hr"; + private static final String SYSTEM_APP_SAFETY_LABEL_OD_PATH = + "com/android/asllib/systemappsafetylabel/od"; + + private static final String VALID_FILE_NAME = "valid.xml"; + private static final String MISSING_BOOL_FILE_NAME = "missing-bool.xml"; + + /** Logic for setting up tests (empty if not yet needed). */ + public static void main(String[] params) throws Exception {} + + @Before + public void setUp() throws Exception { + System.out.println("set up."); + } + + /** Test for valid. */ + @Test + public void testValid() throws Exception { + System.out.println("starting testValid."); + testHrToOdSystemAppSafetyLabel(VALID_FILE_NAME); + testOdToHrSystemAppSafetyLabel(VALID_FILE_NAME); + } + + /** Tests missing bool. */ + @Test + public void testMissingBool() throws Exception { + System.out.println("starting testMissingBool."); + hrToOdExpectException(MISSING_BOOL_FILE_NAME); + odToHrExpectException(MISSING_BOOL_FILE_NAME); + } + + private void hrToOdExpectException(String fileName) { + TestUtils.hrToOdExpectException( + new SystemAppSafetyLabelFactory(), SYSTEM_APP_SAFETY_LABEL_HR_PATH, fileName); + } + + private void odToHrExpectException(String fileName) { + TestUtils.odToHrExpectException( + new SystemAppSafetyLabelFactory(), SYSTEM_APP_SAFETY_LABEL_OD_PATH, fileName); + } + + private void testHrToOdSystemAppSafetyLabel(String fileName) throws Exception { + TestUtils.testHrToOd( + TestUtils.document(), + new SystemAppSafetyLabelFactory(), + SYSTEM_APP_SAFETY_LABEL_HR_PATH, + SYSTEM_APP_SAFETY_LABEL_OD_PATH, + fileName); + } + + private void testOdToHrSystemAppSafetyLabel(String fileName) throws Exception { + TestUtils.testOdToHr( + TestUtils.document(), + new SystemAppSafetyLabelFactory(), + SYSTEM_APP_SAFETY_LABEL_OD_PATH, + SYSTEM_APP_SAFETY_LABEL_HR_PATH, + fileName); + } +} diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/ThirdPartyVerificationTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/ThirdPartyVerificationTest.java new file mode 100644 index 000000000000..ec86d0f863af --- /dev/null +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/ThirdPartyVerificationTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2017 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.asllib.marshallable; + +import com.android.asllib.testutils.TestUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ThirdPartyVerificationTest { + private static final String THIRD_PARTY_VERIFICATION_HR_PATH = + "com/android/asllib/thirdpartyverification/hr"; + private static final String THIRD_PARTY_VERIFICATION_OD_PATH = + "com/android/asllib/thirdpartyverification/od"; + + private static final String VALID_FILE_NAME = "valid.xml"; + private static final String MISSING_URL_FILE_NAME = "missing-url.xml"; + + /** Logic for setting up tests (empty if not yet needed). */ + public static void main(String[] params) throws Exception {} + + @Before + public void setUp() throws Exception { + System.out.println("set up."); + } + + /** Test for valid. */ + @Test + public void testValid() throws Exception { + System.out.println("starting testValid."); + testHrToOdThirdPartyVerification(VALID_FILE_NAME); + testOdToHrThirdPartyVerification(VALID_FILE_NAME); + } + + /** Tests missing url. */ + @Test + public void testMissingUrl() throws Exception { + System.out.println("starting testMissingUrl."); + hrToOdExpectException(MISSING_URL_FILE_NAME); + odToHrExpectException(MISSING_URL_FILE_NAME); + } + + private void hrToOdExpectException(String fileName) { + TestUtils.hrToOdExpectException( + new ThirdPartyVerificationFactory(), THIRD_PARTY_VERIFICATION_HR_PATH, fileName); + } + + private void odToHrExpectException(String fileName) { + TestUtils.odToHrExpectException( + new ThirdPartyVerificationFactory(), THIRD_PARTY_VERIFICATION_OD_PATH, fileName); + } + + private void testHrToOdThirdPartyVerification(String fileName) throws Exception { + TestUtils.testHrToOd( + TestUtils.document(), + new ThirdPartyVerificationFactory(), + THIRD_PARTY_VERIFICATION_HR_PATH, + THIRD_PARTY_VERIFICATION_OD_PATH, + fileName); + } + + private void testOdToHrThirdPartyVerification(String fileName) throws Exception { + TestUtils.testOdToHr( + TestUtils.document(), + new ThirdPartyVerificationFactory(), + THIRD_PARTY_VERIFICATION_OD_PATH, + THIRD_PARTY_VERIFICATION_HR_PATH, + fileName); + } +} diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java new file mode 100644 index 000000000000..f49424061427 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2017 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.asllib.marshallable; + +import com.android.asllib.testutils.TestUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class TransparencyInfoTest { + private static final String TRANSPARENCY_INFO_HR_PATH = + "com/android/asllib/transparencyinfo/hr"; + private static final String TRANSPARENCY_INFO_OD_PATH = + "com/android/asllib/transparencyinfo/od"; + + private static final String VALID_EMPTY_FILE_NAME = "valid-empty.xml"; + private static final String WITH_DEVELOPER_INFO_FILE_NAME = "with-developer-info.xml"; + private static final String WITH_APP_INFO_FILE_NAME = "with-app-info.xml"; + + @Before + public void setUp() throws Exception { + System.out.println("set up."); + } + + /** Test for transparency info valid empty. */ + @Test + public void testTransparencyInfoValidEmptyFile() throws Exception { + System.out.println("starting testTransparencyInfoValidEmptyFile."); + testHrToOdTransparencyInfo(VALID_EMPTY_FILE_NAME); + testOdToHrTransparencyInfo(VALID_EMPTY_FILE_NAME); + } + + /** Test for transparency info with developer info. */ + @Test + public void testTransparencyInfoWithDeveloperInfo() throws Exception { + System.out.println("starting testTransparencyInfoWithDeveloperInfo."); + testHrToOdTransparencyInfo(WITH_DEVELOPER_INFO_FILE_NAME); + testOdToHrTransparencyInfo(WITH_DEVELOPER_INFO_FILE_NAME); + } + + /** Test for transparency info with app info. */ + @Test + public void testTransparencyInfoWithAppInfo() throws Exception { + System.out.println("starting testTransparencyInfoWithAppInfo."); + testHrToOdTransparencyInfo(WITH_APP_INFO_FILE_NAME); + testOdToHrTransparencyInfo(WITH_APP_INFO_FILE_NAME); + } + + private void testHrToOdTransparencyInfo(String fileName) throws Exception { + TestUtils.testHrToOd( + TestUtils.document(), + new TransparencyInfoFactory(), + TRANSPARENCY_INFO_HR_PATH, + TRANSPARENCY_INFO_OD_PATH, + fileName); + } + + private void testOdToHrTransparencyInfo(String fileName) throws Exception { + TestUtils.testOdToHr( + TestUtils.document(), + new TransparencyInfoFactory(), + TRANSPARENCY_INFO_OD_PATH, + TRANSPARENCY_INFO_HR_PATH, + fileName); + } +} diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java new file mode 100644 index 000000000000..ea90993e0785 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2017 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.asllib.testutils; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import com.android.asllib.marshallable.AslMarshallable; +import com.android.asllib.marshallable.AslMarshallableFactory; +import com.android.asllib.util.MalformedXmlException; +import com.android.asllib.util.XmlUtils; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Optional; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +public class TestUtils { + public static final String HOLDER_TAG_NAME = "holder_of_flattened_for_testing"; + + /** Reads a Resource file into a String. */ + public static String readStrFromResource(Path filePath) throws IOException { + InputStream hrStream = + TestUtils.class.getClassLoader().getResourceAsStream(filePath.toString()); + return new String(hrStream.readAllBytes(), StandardCharsets.UTF_8); + } + + /** Gets List of Element from a path to an existing Resource. */ + public static List<Element> getElementsFromResource(Path filePath) + throws ParserConfigurationException, IOException, SAXException { + String str = readStrFromResource(filePath); + InputStream stream = new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8)); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + Document document = factory.newDocumentBuilder().parse(stream); + Element root = document.getDocumentElement(); + if (root.getTagName().equals(HOLDER_TAG_NAME)) { + String tagName = + XmlUtils.asElementList(root.getChildNodes()).stream() + .findFirst() + .get() + .getTagName(); + return XmlUtils.getChildrenByTagName(root, tagName); + } else { + return List.of(root); + } + } + + /** Reads a Document into a String. */ + public static String docToStr(Document doc, boolean omitXmlDeclaration) + throws TransformerException { + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer = transformerFactory.newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + transformer.setOutputProperty( + OutputKeys.OMIT_XML_DECLARATION, omitXmlDeclaration ? "yes" : "no"); + + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + StreamResult streamResult = new StreamResult(outStream); // out + DOMSource domSource = new DOMSource(doc); + transformer.transform(domSource, streamResult); + + return outStream.toString(StandardCharsets.UTF_8); + } + + /** Removes on-device style child with the corresponding name */ + public static void removeOdChildEleWithName(Element ele, String childNameName) { + Optional<Element> childEle = + XmlUtils.asElementList(ele.getChildNodes()).stream() + .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(childNameName)) + .findFirst(); + if (childEle.isEmpty()) { + throw new IllegalStateException( + String.format("%s was not found in %s", childNameName, ele.getTagName())); + } + ele.removeChild(childEle.get()); + } + + /** + * Gets formatted XML for slightly more robust comparison checking than naive string comparison. + */ + public static String getFormattedXml(String xmlStr, boolean omitXmlDeclaration) + throws ParserConfigurationException, IOException, SAXException, TransformerException { + InputStream stream = new ByteArrayInputStream(xmlStr.getBytes(StandardCharsets.UTF_8)); + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + Document document = factory.newDocumentBuilder().parse(stream); + stripEmptyElements(document); + return docToStr(document, omitXmlDeclaration); + } + + /** Helper for getting a new Document */ + public static Document document() throws ParserConfigurationException { + return DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); + } + + /** Helper for testing human-readable to on-device conversion expecting exception */ + public static <T extends AslMarshallable> void hrToOdExpectException( + AslMarshallableFactory<T> factory, String hrFolderPath, String fileName) { + assertThrows( + MalformedXmlException.class, + () -> { + factory.createFromHrElements( + TestUtils.getElementsFromResource(Paths.get(hrFolderPath, fileName))); + }); + } + + /** Helper for testing on-device to human-readable conversion expecting exception */ + public static <T extends AslMarshallable> void odToHrExpectException( + AslMarshallableFactory<T> factory, String odFolderPath, String fileName) { + assertThrows( + MalformedXmlException.class, + () -> { + factory.createFromOdElements( + TestUtils.getElementsFromResource(Paths.get(odFolderPath, fileName))); + }); + } + + /** Helper for testing human-readable to on-device conversion */ + public static <T extends AslMarshallable> void testHrToOd( + Document doc, + AslMarshallableFactory<T> factory, + String hrFolderPath, + String odFolderPath, + String fileName) + throws Exception { + testFormatToFormat(doc, factory, hrFolderPath, odFolderPath, fileName, true); + } + + /** Helper for testing on-device to human-readable conversion */ + public static <T extends AslMarshallable> void testOdToHr( + Document doc, + AslMarshallableFactory<T> factory, + String odFolderPath, + String hrFolderPath, + String fileName) + throws Exception { + testFormatToFormat(doc, factory, odFolderPath, hrFolderPath, fileName, false); + } + + /** Helper for testing format to format conversion */ + private static <T extends AslMarshallable> void testFormatToFormat( + Document doc, + AslMarshallableFactory<T> factory, + String inFolderPath, + String outFolderPath, + String fileName, + boolean hrToOd) + throws Exception { + AslMarshallable marshallable = + hrToOd + ? factory.createFromHrElements( + TestUtils.getElementsFromResource( + Paths.get(inFolderPath, fileName))) + : factory.createFromOdElements( + TestUtils.getElementsFromResource( + Paths.get(inFolderPath, fileName))); + + List<Element> elements = + hrToOd ? marshallable.toOdDomElements(doc) : marshallable.toHrDomElements(doc); + if (elements.isEmpty()) { + throw new IllegalStateException("elements was empty."); + } else if (elements.size() == 1) { + doc.appendChild(elements.get(0)); + } else { + Element root = doc.createElement(TestUtils.HOLDER_TAG_NAME); + for (var child : elements) { + root.appendChild(child); + } + doc.appendChild(root); + } + String converted = TestUtils.getFormattedXml(TestUtils.docToStr(doc, true), true); + System.out.println("Converted: " + converted); + String expectedOutContents = + TestUtils.getFormattedXml( + TestUtils.readStrFromResource(Paths.get(outFolderPath, fileName)), true); + System.out.println("Expected: " + expectedOutContents); + assertEquals(expectedOutContents, converted); + } + + private static void stripEmptyElements(Node node) { + NodeList children = node.getChildNodes(); + for (int i = 0; i < children.getLength(); ++i) { + Node child = children.item(i); + if (child.getNodeType() == Node.TEXT_NODE) { + if (child.getTextContent().trim().length() == 0) { + child.getParentNode().removeChild(child); + i--; + } + } + stripEmptyElements(child); + } + } +} diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/missing-version.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/missing-version.xml new file mode 100644 index 000000000000..ec0cd702fd43 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/missing-version.xml @@ -0,0 +1,3 @@ +<app-metadata-bundles> + +</app-metadata-bundles>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/valid-empty.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/valid-empty.xml new file mode 100644 index 000000000000..19bfd826f770 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/valid-empty.xml @@ -0,0 +1 @@ +<app-metadata-bundles version="123456"></app-metadata-bundles>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-safety-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-safety-labels.xml new file mode 100644 index 000000000000..53794a1d1c80 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-safety-labels.xml @@ -0,0 +1,4 @@ +<app-metadata-bundles version="123456"> + <safety-labels version="12345"> + </safety-labels> +</app-metadata-bundles>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-system-app-safety-label.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-system-app-safety-label.xml new file mode 100644 index 000000000000..afb048632bc6 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-system-app-safety-label.xml @@ -0,0 +1,4 @@ +<app-metadata-bundles version="123456"> +<system-app-safety-label declaration="true"> +</system-app-safety-label> +</app-metadata-bundles>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-transparency-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-transparency-info.xml new file mode 100644 index 000000000000..00bcfa80e9b1 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-transparency-info.xml @@ -0,0 +1,4 @@ +<app-metadata-bundles version="123456"> +<transparency-info> +</transparency-info> +</app-metadata-bundles>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/missing-version.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/missing-version.xml new file mode 100644 index 000000000000..1aa3aa94ca6d --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/missing-version.xml @@ -0,0 +1,2 @@ +<bundle> +</bundle>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/valid-empty.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/valid-empty.xml new file mode 100644 index 000000000000..37bdfad4065f --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/valid-empty.xml @@ -0,0 +1,3 @@ +<bundle> + <long name="version" value="123456"/> +</bundle>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-safety-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-safety-labels.xml new file mode 100644 index 000000000000..74644ed0413c --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-safety-labels.xml @@ -0,0 +1,6 @@ +<bundle> + <long name="version" value="123456"/> + <pbundle_as_map name="safety_labels"> + <long name="version" value="12345"/> + </pbundle_as_map> +</bundle> diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-system-app-safety-label.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-system-app-safety-label.xml new file mode 100644 index 000000000000..e8640c4f0934 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-system-app-safety-label.xml @@ -0,0 +1,6 @@ +<bundle> + <long name="version" value="123456"/> + <pbundle_as_map name="system_app_safety_label"> + <boolean name="declaration" value="true"/> + </pbundle_as_map> +</bundle>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-transparency-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-transparency-info.xml new file mode 100644 index 000000000000..63c5094333cc --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-transparency-info.xml @@ -0,0 +1,4 @@ +<bundle> + <long name="version" value="123456"/> + <pbundle_as_map name="transparency_info"/> +</bundle>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/hr/all-fields-valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/hr/all-fields-valid.xml new file mode 100644 index 000000000000..883170a2d36f --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/hr/all-fields-valid.xml @@ -0,0 +1,14 @@ +<app-info + title="beervision" + description="a beer app" + containsAds="true" + obeyAps="false" + adsFingerprinting="false" + securityFingerprinting="false" + privacyPolicy="www.example.com" + securityEndpoints="url1|url2|url3" + firstPartyEndpoints="url1" + serviceProviderEndpoints="url55|url56" + category="Food and drink" + email="max@maxloh.com" + website="www.example.com" />
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid.xml new file mode 100644 index 000000000000..6e976a3278de --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid.xml @@ -0,0 +1,25 @@ + +<pbundle_as_map name="app_info"> + <string name="title" value="beervision"/> + <string name="description" value="a beer app"/> + <boolean name="contains_ads" value="true"/> + <boolean name="obey_aps" value="false"/> + <boolean name="ads_fingerprinting" value="false"/> + <boolean name="security_fingerprinting" value="false"/> + <string name="privacy_policy" value="www.example.com"/> + <string-array name="security_endpoint" num="3"> + <item value="url1"/> + <item value="url2"/> + <item value="url3"/> + </string-array> + <string-array name="first_party_endpoint" num="1"> + <item value="url1"/> + </string-array> + <string-array name="service_provider_endpoint" num="2"> + <item value="url55"/> + <item value="url56"/> + </string-array> + <string name="category" value="Food and drink"/> + <string name="email" value="max@maxloh.com"/> + <string name="website" value="www.example.com"/> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-actions-in-app.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-actions-in-app.xml new file mode 100644 index 000000000000..520e525679b8 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-actions-in-app.xml @@ -0,0 +1,17 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="actions_in_app" + dataType="user_interaction" + purposes="analytics" /> + <data-shared dataCategory="actions_in_app" + dataType="in_app_search_history" + purposes="analytics" /> + <data-shared dataCategory="actions_in_app" + dataType="installed_apps" + purposes="analytics" /> + <data-shared dataCategory="actions_in_app" + dataType="user_generated_content" + purposes="analytics" /> + <data-shared dataCategory="actions_in_app" + dataType="other" + purposes="analytics" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-app-performance.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-app-performance.xml new file mode 100644 index 000000000000..0d08e5b5ae4d --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-app-performance.xml @@ -0,0 +1,11 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="app_performance" + dataType="crash_logs" + purposes="analytics" /> + <data-shared dataCategory="app_performance" + dataType="performance_diagnostics" + purposes="analytics" /> + <data-shared dataCategory="app_performance" + dataType="other" + purposes="analytics" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-audio.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-audio.xml new file mode 100644 index 000000000000..b1cf3b44fd4a --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-audio.xml @@ -0,0 +1,11 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="audio" + dataType="sound_recordings" + purposes="analytics" /> + <data-shared dataCategory="audio" + dataType="music_files" + purposes="analytics" /> + <data-shared dataCategory="audio" + dataType="other" + purposes="analytics" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-calendar.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-calendar.xml new file mode 100644 index 000000000000..a723070c43b7 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-calendar.xml @@ -0,0 +1,5 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="calendar" + dataType="calendar" + purposes="analytics" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-contacts.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-contacts.xml new file mode 100644 index 000000000000..2fe28ffe4940 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-contacts.xml @@ -0,0 +1,5 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="contacts" + dataType="contacts" + purposes="analytics" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-email-text-message.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-email-text-message.xml new file mode 100644 index 000000000000..49a326fc43e5 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-email-text-message.xml @@ -0,0 +1,11 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="email_text_message" + dataType="emails" + purposes="analytics" /> + <data-shared dataCategory="email_text_message" + dataType="text_messages" + purposes="analytics" /> + <data-shared dataCategory="email_text_message" + dataType="other" + purposes="analytics" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-financial.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-financial.xml new file mode 100644 index 000000000000..f5de3707ef8a --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-financial.xml @@ -0,0 +1,14 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="financial" + dataType="card_bank_account" + purposes="analytics" /> + <data-shared dataCategory="financial" + dataType="purchase_history" + purposes="analytics" /> + <data-shared dataCategory="financial" + dataType="credit_score" + purposes="analytics" /> + <data-shared dataCategory="financial" + dataType="other" + purposes="analytics" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-health-fitness.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-health-fitness.xml new file mode 100644 index 000000000000..9891f8170bd7 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-health-fitness.xml @@ -0,0 +1,8 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="health_fitness" + dataType="health" + purposes="analytics" /> + <data-shared dataCategory="health_fitness" + dataType="fitness" + purposes="analytics" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-identifiers.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-identifiers.xml new file mode 100644 index 000000000000..3e74da1ad527 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-identifiers.xml @@ -0,0 +1,5 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="identifiers" + dataType="other" + purposes="analytics" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-location.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-location.xml new file mode 100644 index 000000000000..4762f16d64db --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-location.xml @@ -0,0 +1,8 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="location" + dataType="approx_location" + purposes="analytics" /> + <data-shared dataCategory="location" + dataType="precise_location" + purposes="analytics" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-personal-empty-purpose.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-personal-empty-purpose.xml new file mode 100644 index 000000000000..964e178e4dbd --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-personal-empty-purpose.xml @@ -0,0 +1,5 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="personal" + dataType="email_address" + purposes="" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-personal-missing-purpose.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-personal-missing-purpose.xml new file mode 100644 index 000000000000..3ce1288fb2c3 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-personal-missing-purpose.xml @@ -0,0 +1,4 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="personal" + dataType="email_address" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-personal-partial.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-personal-partial.xml new file mode 100644 index 000000000000..68baae30ef4f --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-personal-partial.xml @@ -0,0 +1,8 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="personal" + dataType="name" + purposes="analytics|developer_communications" /> + <data-shared dataCategory="personal" + dataType="email_address" + purposes="analytics" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-personal-unrecognized-type.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-personal-unrecognized-type.xml new file mode 100644 index 000000000000..921a90a3fde7 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-personal-unrecognized-type.xml @@ -0,0 +1,5 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="personal" + dataType="unrecognized" + purposes="analytics" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-personal.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-personal.xml new file mode 100644 index 000000000000..4533773ec9c1 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-personal.xml @@ -0,0 +1,31 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="personal" + dataType="name" + ephemeral="true" + isCollectionOptional="true" + purposes="analytics|developer_communications" /> + <data-shared dataCategory="personal" + dataType="email_address" + purposes="analytics" /> + <data-shared dataCategory="personal" + dataType="physical_address" + purposes="analytics" /> + <data-shared dataCategory="personal" + dataType="phone_number" + purposes="analytics" /> + <data-shared dataCategory="personal" + dataType="race_ethnicity" + purposes="analytics" /> + <data-shared dataCategory="personal" + dataType="political_or_religious_beliefs" + purposes="analytics" /> + <data-shared dataCategory="personal" + dataType="sexual_orientation_or_gender_identity" + purposes="analytics" /> + <data-shared dataCategory="personal" + dataType="personal_identifiers" + purposes="analytics" /> + <data-shared dataCategory="personal" + dataType="other" + purposes="analytics" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-photo-video.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-photo-video.xml new file mode 100644 index 000000000000..234fb265ae55 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-photo-video.xml @@ -0,0 +1,8 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="photo_video" + dataType="photos" + purposes="analytics" /> + <data-shared dataCategory="photo_video" + dataType="videos" + purposes="analytics" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-search-and-browsing.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-search-and-browsing.xml new file mode 100644 index 000000000000..db851633aec5 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-search-and-browsing.xml @@ -0,0 +1,5 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="search_and_browsing" + dataType="web_browsing_history" + purposes="analytics" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-storage.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-storage.xml new file mode 100644 index 000000000000..9aad02de8877 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-storage.xml @@ -0,0 +1,5 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="storage" + dataType="files_docs" + purposes="analytics" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-unrecognized.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-unrecognized.xml new file mode 100644 index 000000000000..64b9ea72e05b --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/hr/data-category-unrecognized.xml @@ -0,0 +1,5 @@ +<holder_of_flattened_for_testing> + <data-shared dataCategory="unrecognized" + dataType="email_address" + purposes="analytics" /> +</holder_of_flattened_for_testing>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-actions-in-app.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-actions-in-app.xml new file mode 100644 index 000000000000..5b99900b5a8a --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-actions-in-app.xml @@ -0,0 +1,27 @@ +<pbundle_as_map name="actions_in_app"> + <pbundle_as_map name="user_interaction"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="in_app_search_history"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="installed_apps"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="user_generated_content"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="other"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-app-performance.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-app-performance.xml new file mode 100644 index 000000000000..0fe102202be5 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-app-performance.xml @@ -0,0 +1,17 @@ +<pbundle_as_map name="app_performance"> + <pbundle_as_map name="crash_logs"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="performance_diagnostics"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="other"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-audio.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-audio.xml new file mode 100644 index 000000000000..51f1dfd6d823 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-audio.xml @@ -0,0 +1,17 @@ +<pbundle_as_map name="audio"> + <pbundle_as_map name="sound_recordings"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="music_files"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="other"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-calendar.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-calendar.xml new file mode 100644 index 000000000000..326da47a1cb9 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-calendar.xml @@ -0,0 +1,7 @@ +<pbundle_as_map name="calendar"> + <pbundle_as_map name="calendar"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-contacts.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-contacts.xml new file mode 100644 index 000000000000..5d4387d2f906 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-contacts.xml @@ -0,0 +1,7 @@ +<pbundle_as_map name="contacts"> + <pbundle_as_map name="contacts"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-email-text-message.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-email-text-message.xml new file mode 100644 index 000000000000..5ac98f56ace6 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-email-text-message.xml @@ -0,0 +1,17 @@ +<pbundle_as_map name="email_text_message"> + <pbundle_as_map name="emails"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="text_messages"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="other"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-financial.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-financial.xml new file mode 100644 index 000000000000..a66f1a44dcb3 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-financial.xml @@ -0,0 +1,22 @@ +<pbundle_as_map name="financial"> + <pbundle_as_map name="card_bank_account"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="purchase_history"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="credit_score"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="other"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-health-fitness.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-health-fitness.xml new file mode 100644 index 000000000000..8e697b47364c --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-health-fitness.xml @@ -0,0 +1,12 @@ +<pbundle_as_map name="health_fitness"> + <pbundle_as_map name="health"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="fitness"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-identifiers.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-identifiers.xml new file mode 100644 index 000000000000..34b4016e1364 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-identifiers.xml @@ -0,0 +1,7 @@ +<pbundle_as_map name="identifiers"> + <pbundle_as_map name="other"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-location.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-location.xml new file mode 100644 index 000000000000..db2e6965ff2a --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-location.xml @@ -0,0 +1,12 @@ +<pbundle_as_map name="location"> + <pbundle_as_map name="approx_location"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="precise_location"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-personal-partial.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-personal-partial.xml new file mode 100644 index 000000000000..839922a8bec6 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-personal-partial.xml @@ -0,0 +1,13 @@ +<pbundle_as_map name="personal"> + <pbundle_as_map name="name"> + <int-array name="purposes" num="2"> + <item value="2" /> + <item value="3" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="email_address"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-personal.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-personal.xml new file mode 100644 index 000000000000..43650b6a77fe --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-personal.xml @@ -0,0 +1,50 @@ +<pbundle_as_map name="personal"> + <pbundle_as_map name="name"> + <int-array name="purposes" num="2"> + <item value="2" /> + <item value="3" /> + </int-array> + <boolean name="is_collection_optional" value="true" /> + <boolean name="ephemeral" value="true" /> + </pbundle_as_map> + <pbundle_as_map name="email_address"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="physical_address"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="phone_number"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="race_ethnicity"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="political_or_religious_beliefs"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="sexual_orientation_or_gender_identity"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="personal_identifiers"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="other"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-photo-video.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-photo-video.xml new file mode 100644 index 000000000000..2a3178005df3 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-photo-video.xml @@ -0,0 +1,12 @@ +<pbundle_as_map name="photo_video"> + <pbundle_as_map name="photos"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="videos"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-search-and-browsing.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-search-and-browsing.xml new file mode 100644 index 000000000000..9e654efcc5ab --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-search-and-browsing.xml @@ -0,0 +1,7 @@ +<pbundle_as_map name="search_and_browsing"> + <pbundle_as_map name="web_browsing_history"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-storage.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-storage.xml new file mode 100644 index 000000000000..9abc37fdb2b9 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datacategory/od/data-category-storage.xml @@ -0,0 +1,7 @@ +<pbundle_as_map name="storage"> + <pbundle_as_map name="files_docs"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-actions-in-app.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-actions-in-app.xml new file mode 100644 index 000000000000..680e01a97af3 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-actions-in-app.xml @@ -0,0 +1,12 @@ +<data-labels> + <data-shared dataType="actions_in_app_data_type_user_interaction" + purposes="analytics" /> + <data-shared dataType="actions_in_app_data_type_in_app_search_history" + purposes="analytics" /> + <data-shared dataType="actions_in_app_data_type_installed_apps" + purposes="analytics" /> + <data-shared dataType="actions_in_app_data_type_user_generated_content" + purposes="analytics" /> + <data-shared dataType="actions_in_app_data_type_other" + purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-app-performance.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-app-performance.xml new file mode 100644 index 000000000000..db114bfe15db --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-app-performance.xml @@ -0,0 +1,8 @@ +<data-labels> + <data-shared dataType="app_performance_data_type_crash_logs" + purposes="analytics" /> + <data-shared dataType="app_performance_data_type_performance_diagnostics" + purposes="analytics" /> + <data-shared dataType="app_performance_data_type_other" + purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-audio.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-audio.xml new file mode 100644 index 000000000000..cf273f4dada0 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-audio.xml @@ -0,0 +1,8 @@ +<data-labels> + <data-shared dataType="audio_data_type_sound_recordings" + purposes="analytics" /> + <data-shared dataType="audio_data_type_music_files" + purposes="analytics" /> + <data-shared dataType="audio_data_type_other" + purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-calendar.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-calendar.xml new file mode 100644 index 000000000000..16f9d9b699e4 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-calendar.xml @@ -0,0 +1,4 @@ +<data-labels> + <data-shared dataType="calendar_data_type_calendar" + purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-contacts.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-contacts.xml new file mode 100644 index 000000000000..6d7a4e8c976d --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-contacts.xml @@ -0,0 +1,4 @@ +<data-labels> + <data-shared dataType="contacts_data_type_contacts" + purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-email-text-message.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-email-text-message.xml new file mode 100644 index 000000000000..7a9e978afd10 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-email-text-message.xml @@ -0,0 +1,8 @@ +<data-labels> + <data-shared dataType="email_text_message_data_type_emails" + purposes="analytics" /> + <data-shared dataType="email_text_message_data_type_text_messages" + purposes="analytics" /> + <data-shared dataType="email_text_message_data_type_other" + purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-financial.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-financial.xml new file mode 100644 index 000000000000..24385b64fe6c --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-financial.xml @@ -0,0 +1,10 @@ +<data-labels> + <data-shared dataType="financial_data_type_card_bank_account" + purposes="analytics" /> + <data-shared dataType="financial_data_type_purchase_history" + purposes="analytics" /> + <data-shared dataType="financial_data_type_credit_score" + purposes="analytics" /> + <data-shared dataType="financial_data_type_other" + purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-health-fitness.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-health-fitness.xml new file mode 100644 index 000000000000..faf30b059eef --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-health-fitness.xml @@ -0,0 +1,6 @@ +<data-labels> + <data-shared dataType="health_fitness_data_type_health" + purposes="analytics" /> + <data-shared dataType="health_fitness_data_type_fitness" + purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-identifiers.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-identifiers.xml new file mode 100644 index 000000000000..510190660bef --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-identifiers.xml @@ -0,0 +1,4 @@ +<data-labels> + <data-shared dataType="identifiers_data_type_other" + purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-location.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-location.xml new file mode 100644 index 000000000000..72cda7e40deb --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-location.xml @@ -0,0 +1,6 @@ +<data-labels> + <data-shared dataType="location_data_type_approx_location" + purposes="analytics" /> + <data-shared dataType="location_data_type_precise_location" + purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-empty-purpose.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-empty-purpose.xml new file mode 100644 index 000000000000..25586814c966 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-empty-purpose.xml @@ -0,0 +1,4 @@ +<data-labels> + <data-shared dataType="personal_data_type_email_address" + purposes="" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-missing-purpose.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-missing-purpose.xml new file mode 100644 index 000000000000..c5a54755387b --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-missing-purpose.xml @@ -0,0 +1,3 @@ +<data-labels> + <data-shared dataType="personal_data_type_email_address" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-partial.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-partial.xml new file mode 100644 index 000000000000..6ccf336f8556 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-partial.xml @@ -0,0 +1,6 @@ +<data-labels> + <data-shared dataType="personal_data_type_name" + purposes="analytics|developer_communications" /> + <data-shared dataType="personal_data_type_email_address" + purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-unrecognized-type.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-unrecognized-type.xml new file mode 100644 index 000000000000..bd88adafea60 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-unrecognized-type.xml @@ -0,0 +1,4 @@ +<data-labels> + <data-shared dataType="personal_data_type_unrecognized" + purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal.xml new file mode 100644 index 000000000000..742ed86ed4e5 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal.xml @@ -0,0 +1,21 @@ +<data-labels> + <data-shared dataType="personal_data_type_name" + isSharingOptional="true" + purposes="analytics|developer_communications" /> + <data-shared dataType="personal_data_type_email_address" + purposes="analytics" /> + <data-shared dataType="personal_data_type_physical_address" + purposes="analytics" /> + <data-shared dataType="personal_data_type_phone_number" + purposes="analytics" /> + <data-shared dataType="personal_data_type_race_ethnicity" + purposes="analytics" /> + <data-shared dataType="personal_data_type_political_or_religious_beliefs" + purposes="analytics" /> + <data-shared dataType="personal_data_type_sexual_orientation_or_gender_identity" + purposes="analytics" /> + <data-shared dataType="personal_data_type_personal_identifiers" + purposes="analytics" /> + <data-shared dataType="personal_data_type_other" + purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-photo-video.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-photo-video.xml new file mode 100644 index 000000000000..d416063b87da --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-photo-video.xml @@ -0,0 +1,6 @@ +<data-labels> + <data-shared dataType="photo_video_data_type_photos" + purposes="analytics" /> + <data-shared dataType="photo_video_data_type_videos" + purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-search-and-browsing.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-search-and-browsing.xml new file mode 100644 index 000000000000..3d932d6d01bf --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-search-and-browsing.xml @@ -0,0 +1,4 @@ +<data-labels> + <data-shared dataType="search_and_browsing_data_type_web_browsing_history" + purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-storage.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-storage.xml new file mode 100644 index 000000000000..704cb1c4674e --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-storage.xml @@ -0,0 +1,4 @@ +<data-labels> + <data-shared dataType="storage_data_type_files_docs" + purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-unrecognized-type.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-unrecognized-type.xml new file mode 100644 index 000000000000..bd88adafea60 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-unrecognized-type.xml @@ -0,0 +1,4 @@ +<data-labels> + <data-shared dataType="personal_data_type_unrecognized" + purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-unrecognized.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-unrecognized.xml new file mode 100644 index 000000000000..a578d7343f28 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-unrecognized.xml @@ -0,0 +1,4 @@ +<data-labels> + <data-shared dataType="unrecognized_data_type_email_address" + purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-accessed-collected-shared.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-accessed-collected-shared.xml new file mode 100644 index 000000000000..c0bd6529eac0 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-accessed-collected-shared.xml @@ -0,0 +1,8 @@ +<data-labels> + <data-accessed dataType="location_data_type_approx_location" + purposes="app_functionality" /> + <data-collected dataType="location_data_type_precise_location" + purposes="app_functionality" /> + <data-shared dataType="personal_data_type_name" + purposes="app_functionality" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-accessed-invalid-bool.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-accessed-invalid-bool.xml new file mode 100644 index 000000000000..d09fc3b48f51 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-accessed-invalid-bool.xml @@ -0,0 +1,5 @@ +<data-labels> + <data-accessed dataType="location_data_type_approx_location" + isSharingOptional="false" + purposes="app_functionality" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-accessed-valid-bool.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-accessed-valid-bool.xml new file mode 100644 index 000000000000..6e7f81257116 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-accessed-valid-bool.xml @@ -0,0 +1,4 @@ +<data-labels> + <data-accessed dataType="location_data_type_approx_location" + purposes="app_functionality" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-collected-ephemeral-collision.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-collected-ephemeral-collision.xml new file mode 100644 index 000000000000..ee362feb2ca5 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-collected-ephemeral-collision.xml @@ -0,0 +1,14 @@ +<data-labels> + <data-collected dataType="photo_video_data_type_photos" + isCollectionOptional="true" + purposes="app_functionality" /> + <data-collected-ephemeral dataType="location_data_type_approx_location" + isCollectionOptional="false" + purposes="app_functionality" /> + <data-collected dataType="location_data_type_approx_location" + isCollectionOptional="true" + purposes="app_functionality" /> + <data-collected-ephemeral dataType="contacts_data_type_contacts" + isCollectionOptional="true" + purposes="app_functionality" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-collected-ephemeral.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-collected-ephemeral.xml new file mode 100644 index 000000000000..79c900027666 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-collected-ephemeral.xml @@ -0,0 +1,14 @@ +<data-labels> + <data-collected dataType="photo_video_data_type_photos" + isCollectionOptional="true" + purposes="app_functionality" /> + <data-collected dataType="location_data_type_precise_location" + isCollectionOptional="true" + purposes="app_functionality" /> + <data-collected-ephemeral dataType="location_data_type_approx_location" + isCollectionOptional="false" + purposes="app_functionality" /> + <data-collected-ephemeral dataType="contacts_data_type_contacts" + isCollectionOptional="true" + purposes="app_functionality" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-collected-invalid-bool.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-collected-invalid-bool.xml new file mode 100644 index 000000000000..801fadaadcdd --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-collected-invalid-bool.xml @@ -0,0 +1,5 @@ +<data-labels> + <data-collected dataType="location_data_type_approx_location" + isSharingOptional="false" + purposes="app_functionality" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-collected-valid-bool.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-collected-valid-bool.xml new file mode 100644 index 000000000000..1ada12db0af8 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-collected-valid-bool.xml @@ -0,0 +1,5 @@ +<data-labels> + <data-collected dataType="location_data_type_approx_location" + isCollectionOptional="false" + purposes="app_functionality" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-shared-invalid-bool.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-shared-invalid-bool.xml new file mode 100644 index 000000000000..b327d88b2b8a --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-shared-invalid-bool.xml @@ -0,0 +1,5 @@ +<data-labels> + <data-shared dataType="location_data_type_approx_location" + isCollectionOptional="false" + purposes="app_functionality" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-shared-valid-bool.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-shared-valid-bool.xml new file mode 100644 index 000000000000..34bd0de2bf51 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-shared-valid-bool.xml @@ -0,0 +1,5 @@ +<data-labels> + <data-shared dataType="location_data_type_approx_location" + isSharingOptional="false" + purposes="app_functionality" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-actions-in-app.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-actions-in-app.xml new file mode 100644 index 000000000000..c5fef58cb25c --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-actions-in-app.xml @@ -0,0 +1,31 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="actions_in_app"> + <pbundle_as_map name="user_interaction"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="in_app_search_history"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="installed_apps"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="user_generated_content"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="other"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-app-performance.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-app-performance.xml new file mode 100644 index 000000000000..4570145a0436 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-app-performance.xml @@ -0,0 +1,21 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="app_performance"> + <pbundle_as_map name="crash_logs"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="performance_diagnostics"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="other"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-audio.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-audio.xml new file mode 100644 index 000000000000..120f626549f7 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-audio.xml @@ -0,0 +1,21 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="audio"> + <pbundle_as_map name="sound_recordings"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="music_files"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="other"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-calendar.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-calendar.xml new file mode 100644 index 000000000000..59eb93812690 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-calendar.xml @@ -0,0 +1,11 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="calendar"> + <pbundle_as_map name="calendar"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-contacts.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-contacts.xml new file mode 100644 index 000000000000..f952bfb4df79 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-contacts.xml @@ -0,0 +1,11 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="contacts"> + <pbundle_as_map name="contacts"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-email-text-message.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-email-text-message.xml new file mode 100644 index 000000000000..bcaa716559d4 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-email-text-message.xml @@ -0,0 +1,21 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="email_text_message"> + <pbundle_as_map name="emails"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="text_messages"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="other"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-financial.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-financial.xml new file mode 100644 index 000000000000..a7bc82e38dac --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-financial.xml @@ -0,0 +1,26 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="financial"> + <pbundle_as_map name="card_bank_account"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="purchase_history"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="credit_score"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="other"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-health-fitness.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-health-fitness.xml new file mode 100644 index 000000000000..f3ab2bd90733 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-health-fitness.xml @@ -0,0 +1,16 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="health_fitness"> + <pbundle_as_map name="health"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="fitness"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-identifiers.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-identifiers.xml new file mode 100644 index 000000000000..05c07e54c5a8 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-identifiers.xml @@ -0,0 +1,11 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="identifiers"> + <pbundle_as_map name="other"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-location.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-location.xml new file mode 100644 index 000000000000..931d1adc0218 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-location.xml @@ -0,0 +1,16 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="location"> + <pbundle_as_map name="approx_location"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="precise_location"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-empty-purpose.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-empty-purpose.xml new file mode 100644 index 000000000000..83f4a67cd54d --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-empty-purpose.xml @@ -0,0 +1,11 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="personal"> + <pbundle_as_map name="email_address"> + + <int-array name="purposes" num="2"> + </int-array> + </pbundle_as_map> +</pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-missing-purpose.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-missing-purpose.xml new file mode 100644 index 000000000000..532f5deee655 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-missing-purpose.xml @@ -0,0 +1,8 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="personal"> + <pbundle_as_map name="email_address"> + </pbundle_as_map> +</pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-partial.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-partial.xml new file mode 100644 index 000000000000..974ea6922fce --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-partial.xml @@ -0,0 +1,17 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="personal"> + <pbundle_as_map name="name"> + <int-array name="purposes" num="2"> + <item value="2" /> + <item value="3" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="email_address"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal.xml new file mode 100644 index 000000000000..62c26ab20c68 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal.xml @@ -0,0 +1,53 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="personal"> + <pbundle_as_map name="name"> + <int-array name="purposes" num="2"> + <item value="2" /> + <item value="3" /> + </int-array> + <boolean name="is_sharing_optional" value="true" /> + </pbundle_as_map> + <pbundle_as_map name="email_address"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="physical_address"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="phone_number"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="race_ethnicity"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="political_or_religious_beliefs"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="sexual_orientation_or_gender_identity"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="personal_identifiers"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="other"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-photo-video.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-photo-video.xml new file mode 100644 index 000000000000..a752b5152c25 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-photo-video.xml @@ -0,0 +1,16 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="photo_video"> + <pbundle_as_map name="photos"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> + <pbundle_as_map name="videos"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-search-and-browsing.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-search-and-browsing.xml new file mode 100644 index 000000000000..99bc1881b4f1 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-search-and-browsing.xml @@ -0,0 +1,11 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="search_and_browsing"> + <pbundle_as_map name="web_browsing_history"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-storage.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-storage.xml new file mode 100644 index 000000000000..a4d2a6249119 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-storage.xml @@ -0,0 +1,11 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="storage"> + <pbundle_as_map name="files_docs"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-unrecognized-type.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-unrecognized-type.xml new file mode 100644 index 000000000000..16195df53b3a --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-unrecognized-type.xml @@ -0,0 +1,11 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="personal"> + <pbundle_as_map name="unrecognized"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-unrecognized.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-unrecognized.xml new file mode 100644 index 000000000000..511940eafd4a --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-unrecognized.xml @@ -0,0 +1,11 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="unrecognized"> + <pbundle_as_map name="email_address"> + <int-array name="purposes" num="1"> + <item value="2" /> + </int-array> + </pbundle_as_map> +</pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-accessed-collected-shared.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-accessed-collected-shared.xml new file mode 100644 index 000000000000..f86dbc1a63b2 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-accessed-collected-shared.xml @@ -0,0 +1,29 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_accessed"> + <pbundle_as_map name="location"> + <pbundle_as_map name="approx_location"> + <int-array name="purposes" num="1"> + <item value="1"/> + </int-array> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> + <pbundle_as_map name="data_collected"> + <pbundle_as_map name="location"> + <pbundle_as_map name="precise_location"> + <int-array name="purposes" num="1"> + <item value="1"/> + </int-array> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="personal"> + <pbundle_as_map name="name"> + <int-array name="purposes" num="1"> + <item value="1"/> + </int-array> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-accessed-valid-bool.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-accessed-valid-bool.xml new file mode 100644 index 000000000000..df000aa2a882 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-accessed-valid-bool.xml @@ -0,0 +1,11 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_accessed"> + <pbundle_as_map name="location"> + <pbundle_as_map name="approx_location"> + <int-array name="purposes" num="1"> + <item value="1"/> + </int-array> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-collected-ephemeral.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-collected-ephemeral.xml new file mode 100644 index 000000000000..c671c4be0f5a --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-collected-ephemeral.xml @@ -0,0 +1,38 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_collected"> + <pbundle_as_map name="photo_video"> + <pbundle_as_map name="photos"> + <int-array name="purposes" num="1"> + <item value="1"/> + </int-array> + <boolean name="is_collection_optional" value="true"/> + <boolean name="ephemeral" value="false"/> + </pbundle_as_map> + </pbundle_as_map> + <pbundle_as_map name="location"> + <pbundle_as_map name="precise_location"> + <int-array name="purposes" num="1"> + <item value="1"/> + </int-array> + <boolean name="is_collection_optional" value="true"/> + <boolean name="ephemeral" value="false"/> + </pbundle_as_map> + <pbundle_as_map name="approx_location"> + <int-array name="purposes" num="1"> + <item value="1"/> + </int-array> + <boolean name="is_collection_optional" value="false"/> + <boolean name="ephemeral" value="true"/> + </pbundle_as_map> + </pbundle_as_map> + <pbundle_as_map name="contacts"> + <pbundle_as_map name="contacts"> + <int-array name="purposes" num="1"> + <item value="1"/> + </int-array> + <boolean name="is_collection_optional" value="true"/> + <boolean name="ephemeral" value="true"/> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-collected-invalid-bool.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-collected-invalid-bool.xml new file mode 100644 index 000000000000..54cc8e7049b2 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-collected-invalid-bool.xml @@ -0,0 +1,13 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_collected"> + <pbundle_as_map name="location"> + <pbundle_as_map name="approx_location"> + <int-array name="purposes" num="1"> + <item value="1"/> + </int-array> + <boolean name="is_sharing_optional" value="false"/> + <boolean name="ephemeral" value="false"/> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-collected-valid-bool.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-collected-valid-bool.xml new file mode 100644 index 000000000000..252c7282da20 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-collected-valid-bool.xml @@ -0,0 +1,13 @@ +<pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_collected"> + <pbundle_as_map name="location"> + <pbundle_as_map name="approx_location"> + <int-array name="purposes" num="1"> + <item value="1"/> + </int-array> + <boolean name="is_collection_optional" value="false"/> + <boolean name="ephemeral" value="false"/> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-shared-valid-bool.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-shared-valid-bool.xml new file mode 100644 index 000000000000..0edd8fa264c7 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-shared-valid-bool.xml @@ -0,0 +1,12 @@ +<pbundle_as_map name="data_labels"> +<pbundle_as_map name="data_shared"> + <pbundle_as_map name="location"> + <pbundle_as_map name="approx_location"> + <int-array name="purposes" num="1"> + <item value="1"/> + </int-array> + <boolean name="is_sharing_optional" value="false"/> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/developerinfo/hr/all-fields-valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/developerinfo/hr/all-fields-valid.xml new file mode 100644 index 000000000000..908d8ea2f53e --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/developerinfo/hr/all-fields-valid.xml @@ -0,0 +1,8 @@ +<developer-info + name="max" + email="max@example.com" + address="111 blah lane" + countryRegion="US" + relationship="aosp" + website="example.com" + registryId="registry_id" />
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/developerinfo/od/all-fields-valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/developerinfo/od/all-fields-valid.xml new file mode 100644 index 000000000000..784ec6156c1d --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/developerinfo/od/all-fields-valid.xml @@ -0,0 +1,9 @@ +<pbundle_as_map name="developer_info"> + <string name="name" value="max"/> + <string name="email" value="max@example.com"/> + <string name="address" value="111 blah lane"/> + <string name="country_region" value="US"/> + <long name="relationship" value="5"/> + <string name="website" value="example.com"/> + <string name="app_developer_registry_id" value="registry_id"/> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/missing-version.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/missing-version.xml new file mode 100644 index 000000000000..762f3bdf7875 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/missing-version.xml @@ -0,0 +1,2 @@ +<safety-labels> +</safety-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/valid-empty.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/valid-empty.xml new file mode 100644 index 000000000000..7decfd4865b1 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/valid-empty.xml @@ -0,0 +1 @@ +<safety-labels version="12345"></safety-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-data-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-data-labels.xml new file mode 100644 index 000000000000..84456daedbd5 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-data-labels.xml @@ -0,0 +1,7 @@ +<safety-labels version="12345"> + <data-labels> + <data-shared dataType="location_data_type_approx_location" + isSharingOptional="false" + purposes="app_functionality" /> + </data-labels> +</safety-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-security-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-security-labels.xml new file mode 100644 index 000000000000..940e48a68ce8 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-security-labels.xml @@ -0,0 +1,6 @@ +<safety-labels version="12345"> + <security-labels + isDataDeletable="true" + isDataEncrypted="false" + /> +</safety-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-third-party-verification.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-third-party-verification.xml new file mode 100644 index 000000000000..bfbc5ae70974 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-third-party-verification.xml @@ -0,0 +1,4 @@ +<safety-labels version="12345"> +<third-party-verification url="www.example.com"> + </third-party-verification> +</safety-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/missing-version.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/missing-version.xml new file mode 100644 index 000000000000..3fbe3599cd82 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/missing-version.xml @@ -0,0 +1,2 @@ +<pbundle_as_map name="safety_labels"> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/valid-empty.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/valid-empty.xml new file mode 100644 index 000000000000..4f03d88a3bd2 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/valid-empty.xml @@ -0,0 +1,3 @@ +<pbundle_as_map name="safety_labels"> + <long name="version" value="12345"/> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-data-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-data-labels.xml new file mode 100644 index 000000000000..fa2a3f841e09 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-data-labels.xml @@ -0,0 +1,15 @@ +<pbundle_as_map name="safety_labels"> + <long name="version" value="12345"/> + <pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="location"> + <pbundle_as_map name="approx_location"> + <int-array name="purposes" num="1"> + <item value="1"/> + </int-array> + <boolean name="is_sharing_optional" value="false"/> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-security-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-security-labels.xml new file mode 100644 index 000000000000..b39c562b30d0 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-security-labels.xml @@ -0,0 +1,7 @@ +<pbundle_as_map name="safety_labels"> + <long name="version" value="12345"/> + <pbundle_as_map name="security_labels"> + <boolean name="is_data_deletable" value="true" /> + <boolean name="is_data_encrypted" value="false" /> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-third-party-verification.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-third-party-verification.xml new file mode 100644 index 000000000000..10653ff5027b --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-third-party-verification.xml @@ -0,0 +1,6 @@ +<pbundle_as_map name="safety_labels"> + <long name="version" value="12345"/> + <pbundle_as_map name="third_party_verification"> + <string name="url" value="www.example.com"/> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/securitylabels/hr/all-fields-valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/securitylabels/hr/all-fields-valid.xml new file mode 100644 index 000000000000..e2fb592cba07 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/securitylabels/hr/all-fields-valid.xml @@ -0,0 +1,4 @@ +<security-labels + isDataDeletable="true" + isDataEncrypted="false"> +</security-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/securitylabels/od/all-fields-valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/securitylabels/od/all-fields-valid.xml new file mode 100644 index 000000000000..7b2f656ec832 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/securitylabels/od/all-fields-valid.xml @@ -0,0 +1,4 @@ +<pbundle_as_map name="security_labels"> + <boolean name="is_data_deletable" value="true" /> + <boolean name="is_data_encrypted" value="false" /> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/hr/missing-bool.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/hr/missing-bool.xml new file mode 100644 index 000000000000..ff26c05abdb0 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/hr/missing-bool.xml @@ -0,0 +1 @@ +<system-app-safety-label></system-app-safety-label>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/hr/valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/hr/valid.xml new file mode 100644 index 000000000000..f01d7d299d4a --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/hr/valid.xml @@ -0,0 +1 @@ +<system-app-safety-label declaration="true"></system-app-safety-label>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/od/missing-bool.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/od/missing-bool.xml new file mode 100644 index 000000000000..33b796552463 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/od/missing-bool.xml @@ -0,0 +1,2 @@ +<pbundle_as_map name="system_app_safety_label"> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/od/valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/od/valid.xml new file mode 100644 index 000000000000..fad631b37e38 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/od/valid.xml @@ -0,0 +1,3 @@ +<pbundle_as_map name="system_app_safety_label"> + <boolean name="declaration" value="true"/> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/hr/missing-url.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/hr/missing-url.xml new file mode 100644 index 000000000000..6738ac2f2446 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/hr/missing-url.xml @@ -0,0 +1 @@ +<third-party-verification></third-party-verification>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/hr/valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/hr/valid.xml new file mode 100644 index 000000000000..2a664f22b916 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/hr/valid.xml @@ -0,0 +1 @@ +<third-party-verification url="www.example.com"></third-party-verification>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/od/missing-url.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/od/missing-url.xml new file mode 100644 index 000000000000..0b5a46f904e4 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/od/missing-url.xml @@ -0,0 +1,2 @@ +<pbundle_as_map name="third_party_verification"> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/od/valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/od/valid.xml new file mode 100644 index 000000000000..dbeb592d7e88 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/od/valid.xml @@ -0,0 +1,3 @@ +<pbundle_as_map name="third_party_verification"> + <string name="url" value="www.example.com"/> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/valid-empty.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/valid-empty.xml new file mode 100644 index 000000000000..254a37fb99e8 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/valid-empty.xml @@ -0,0 +1,4 @@ + +<transparency-info> + +</transparency-info>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-app-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-app-info.xml new file mode 100644 index 000000000000..a7c48fc68cf1 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-app-info.xml @@ -0,0 +1,4 @@ + +<transparency-info> + <app-info title="beervision" description="a beer app" containsAds="true" obeyAps="false" adsFingerprinting="false" securityFingerprinting="false" privacyPolicy="www.example.com" securityEndpoints="url1|url2|url3" firstPartyEndpoints="url1" serviceProviderEndpoints="url55|url56" category="Food and drink" email="max@maxloh.com" /> +</transparency-info>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-developer-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-developer-info.xml new file mode 100644 index 000000000000..d16caaea320f --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-developer-info.xml @@ -0,0 +1,11 @@ + +<transparency-info> + <developer-info + name="max" + email="max@example.com" + address="111 blah lane" + countryRegion="US" + relationship="aosp" + website="example.com" + registryId="registry_id" /> +</transparency-info>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/valid-empty.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/valid-empty.xml new file mode 100644 index 000000000000..af574cf92b3a --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/valid-empty.xml @@ -0,0 +1 @@ +<pbundle_as_map name="transparency_info"/>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info.xml new file mode 100644 index 000000000000..b813641f74f8 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info.xml @@ -0,0 +1,26 @@ + +<pbundle_as_map name="transparency_info"> + <pbundle_as_map name="app_info"> + <string name="title" value="beervision"/> + <string name="description" value="a beer app"/> + <boolean name="contains_ads" value="true"/> + <boolean name="obey_aps" value="false"/> + <boolean name="ads_fingerprinting" value="false"/> + <boolean name="security_fingerprinting" value="false"/> + <string name="privacy_policy" value="www.example.com"/> + <string-array name="security_endpoint" num="3"> + <item value="url1"/> + <item value="url2"/> + <item value="url3"/> + </string-array> + <string-array name="first_party_endpoint" num="1"> + <item value="url1"/> + </string-array> + <string-array name="service_provider_endpoint" num="2"> + <item value="url55"/> + <item value="url56"/> + </string-array> + <string name="category" value="Food and drink"/> + <string name="email" value="max@maxloh.com"/> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-developer-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-developer-info.xml new file mode 100644 index 000000000000..d7a4e1a959b7 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-developer-info.xml @@ -0,0 +1,12 @@ + +<pbundle_as_map name="transparency_info"> + <pbundle_as_map name="developer_info"> + <string name="name" value="max"/> + <string name="email" value="max@example.com"/> + <string name="address" value="111 blah lane"/> + <string name="country_region" value="US"/> + <long name="relationship" value="5"/> + <string name="website" value="example.com"/> + <string name="app_developer_registry_id" value="registry_id"/> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/hr.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/hr.xml new file mode 100644 index 000000000000..b2ff4495a6d2 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/hr.xml @@ -0,0 +1,11 @@ +<app-metadata-bundles version="123"> + <safety-labels version="12345"> + <data-labels> + <data-shared dataCategory="contacts" + dataType="contacts" + isSharingOptional="false" + ephemeral="true" + purposes="analytics" /> + </data-labels> + </safety-labels> +</app-metadata-bundles>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/od.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/od.xml new file mode 100644 index 000000000000..81277bf456a4 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/od.xml @@ -0,0 +1,19 @@ +<bundle> + <long name="version" value="123"/> + <pbundle_as_map name="safety_labels"> + <long name="version" value="12345"/> + <pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="contacts"> + <pbundle_as_map name="contacts"> + <int-array name="purposes" num="1"> + <item value="2"/> + </int-array> + <boolean name="is_sharing_optional" value="false"/> + <boolean name="ephemeral" value="true"/> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> +</bundle>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml new file mode 100644 index 000000000000..41b32b5ed7b0 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml @@ -0,0 +1,33 @@ +<app-metadata-bundles version="123"> + <safety-labels version="12345"> + <data-labels> + <data-shared + dataType="location_data_type_approx_location" + isSharingOptional="false" + purposes="app_functionality" /> + <data-shared + dataType="location_data_type_precise_location" + isSharingOptional="true" + purposes="app_functionality|analytics" /> + </data-labels> + <security-labels + isDataDeletable="true" + isDataEncrypted="false" + /> + <third-party-verification url="www.example.com"> + </third-party-verification> + </safety-labels> + <system-app-safety-label declaration="true"> + </system-app-safety-label> + <transparency-info> + <developer-info + name="max" + email="max@example.com" + address="111 blah lane" + countryRegion="US" + relationship="aosp" + website="example.com" + registryId="registry_id" /> + <app-info title="beervision" description="a beer app" containsAds="true" obeyAps="false" adsFingerprinting="false" securityFingerprinting="false" privacyPolicy="www.example.com" securityEndpoints="url1|url2|url3" firstPartyEndpoints="url1" serviceProviderEndpoints="url55|url56" category="Food and drink" email="max@maxloh.com" /> + </transparency-info> +</app-metadata-bundles>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml new file mode 100644 index 000000000000..c11ac4359ecd --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml @@ -0,0 +1,69 @@ +<bundle> + <long name="version" value="123"/> + <pbundle_as_map name="safety_labels"> + <long name="version" value="12345"/> + <pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="location"> + <pbundle_as_map name="approx_location"> + <int-array name="purposes" num="1"> + <item value="1"/> + </int-array> + <boolean name="is_sharing_optional" value="false"/> + </pbundle_as_map> + <pbundle_as_map name="precise_location"> + <int-array name="purposes" num="2"> + <item value="1"/> + <item value="2"/> + </int-array> + <boolean name="is_sharing_optional" value="true"/> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> + <pbundle_as_map name="security_labels"> + <boolean name="is_data_deletable" value="true"/> + <boolean name="is_data_encrypted" value="false"/> + </pbundle_as_map> + <pbundle_as_map name="third_party_verification"> + <string name="url" value="www.example.com"/> + </pbundle_as_map> + </pbundle_as_map> + <pbundle_as_map name="system_app_safety_label"> + <boolean name="declaration" value="true"/> + </pbundle_as_map> + <pbundle_as_map name="transparency_info"> + <pbundle_as_map name="developer_info"> + <string name="name" value="max"/> + <string name="email" value="max@example.com"/> + <string name="address" value="111 blah lane"/> + <string name="country_region" value="US"/> + <long name="relationship" value="5"/> + <string name="website" value="example.com"/> + <string name="app_developer_registry_id" value="registry_id"/> + </pbundle_as_map> + <pbundle_as_map name="app_info"> + <string name="title" value="beervision"/> + <string name="description" value="a beer app"/> + <boolean name="contains_ads" value="true"/> + <boolean name="obey_aps" value="false"/> + <boolean name="ads_fingerprinting" value="false"/> + <boolean name="security_fingerprinting" value="false"/> + <string name="privacy_policy" value="www.example.com"/> + <string-array name="security_endpoint" num="3"> + <item value="url1"/> + <item value="url2"/> + <item value="url3"/> + </string-array> + <string-array name="first_party_endpoint" num="1"> + <item value="url1"/> + </string-array> + <string-array name="service_provider_endpoint" num="2"> + <item value="url55"/> + <item value="url56"/> + </string-array> + <string name="category" value="Food and drink"/> + <string name="email" value="max@maxloh.com"/> + </pbundle_as_map> + </pbundle_as_map> +</bundle>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/hr.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/hr.xml new file mode 100644 index 000000000000..ac844b3b2767 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/hr.xml @@ -0,0 +1,16 @@ +<app-metadata-bundles version="123"> + <safety-labels version="12345"> + <data-labels> + <data-shared dataCategory="location" + dataType="precise_location" + isSharingOptional="true" + ephemeral="true" + purposes="app_functionality|analytics" /> + <data-shared dataCategory="location" + dataType="approx_location" + isSharingOptional="false" + ephemeral="false" + purposes="app_functionality" /> + </data-labels> + </safety-labels> +</app-metadata-bundles>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/od.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/od.xml new file mode 100644 index 000000000000..d0a3bfa7e64f --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/od.xml @@ -0,0 +1,27 @@ +<bundle> + <long name="version" value="123"/> + <pbundle_as_map name="safety_labels"> + <long name="version" value="12345"/> + <pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="location"> + <pbundle_as_map name="precise_location"> + <int-array name="purposes" num="2"> + <item value="1"/> + <item value="2"/> + </int-array> + <boolean name="is_sharing_optional" value="true"/> + <boolean name="ephemeral" value="true"/> + </pbundle_as_map> + <pbundle_as_map name="approx_location"> + <int-array name="purposes" num="1"> + <item value="1"/> + </int-array> + <boolean name="is_sharing_optional" value="false"/> + <boolean name="ephemeral" value="false"/> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> +</bundle>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/test.xml b/tools/app_metadata_bundles/src/test/resources/test.xml new file mode 100644 index 000000000000..202cc1e1c526 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/test.xml @@ -0,0 +1,16 @@ +<app-metadata-bundles> + <safety-labels version="12345"> + <data-labels> + <data-shared dataCategory="location" + dataType="precise_location" + isSharingOptional="true" + ephemeral="true" + purposes="app_functionality|analytics" /> + <data-shared dataCategory="location" + dataType="approx_location" + isSharingOptional="false" + ephemeral="false" + purposes="app_functionality" /> + </data-labels> + </safety-labels> +</app-metadata-bundles>
\ No newline at end of file diff --git a/tools/codegen/src/com/android/codegen/Main.kt b/tools/codegen/src/com/android/codegen/Main.kt index bcc6230fd53f..bcc6230fd53f 100755..100644 --- a/tools/codegen/src/com/android/codegen/Main.kt +++ b/tools/codegen/src/com/android/codegen/Main.kt diff --git a/tools/hoststubgen/TEST_MAPPING b/tools/hoststubgen/TEST_MAPPING index b5d5b5fb6d92..856e6eefba15 100644 --- a/tools/hoststubgen/TEST_MAPPING +++ b/tools/hoststubgen/TEST_MAPPING @@ -1,14 +1,7 @@ { - "presubmit": [ - // TODO(b/326897452): Reenable after JDK 21 switch. - // { "name": "tiny-framework-dump-test" }, - { "name": "hoststubgentest" }, - { "name": "hoststubgen-invoke-test" } - ], - "ravenwood-presubmit": [ + "imports": [ { - "name": "CtsUtilTestCasesRavenwood", - "host": true + "path": "frameworks/base/ravenwood" } ] } diff --git a/tools/hoststubgen/hoststubgen/Android.bp b/tools/hoststubgen/hoststubgen/Android.bp index 30333da5e86c..682adbc86d06 100644 --- a/tools/hoststubgen/hoststubgen/Android.bp +++ b/tools/hoststubgen/hoststubgen/Android.bp @@ -82,13 +82,30 @@ java_library { jarjar_rules: "jarjar-rules.txt", } +// For sharing the code with other tools +java_library_host { + name: "hoststubgen-lib", + defaults: ["ravenwood-internal-only-visibility-java"], + srcs: ["src/**/*.kt"], + static_libs: [ + "hoststubgen-helper-runtime", + ], + libs: [ + "junit", + "ow2-asm", + "ow2-asm-analysis", + "ow2-asm-commons", + "ow2-asm-tree", + "ow2-asm-util", + ], +} + // Host-side stub generator tool. java_binary_host { name: "hoststubgen", - main_class: "com.android.hoststubgen.Main", - srcs: ["src/**/*.kt"], + main_class: "com.android.hoststubgen.HostStubGenMain", static_libs: [ - "hoststubgen-helper-runtime", + "hoststubgen-lib", "junit", "ow2-asm", "ow2-asm-analysis", diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt index 1089f82b6472..5dde265c79fb 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt @@ -16,6 +16,7 @@ package com.android.hoststubgen import com.android.hoststubgen.asm.ClassNodes +import com.android.hoststubgen.dumper.ApiDumper import com.android.hoststubgen.filters.AnnotationBasedFilter import com.android.hoststubgen.filters.ClassWidePolicyPropagatingFilter import com.android.hoststubgen.filters.ConstantFilter @@ -32,7 +33,8 @@ import com.android.hoststubgen.visitors.PackageRedirectRemapper import org.objectweb.asm.ClassReader import org.objectweb.asm.ClassVisitor import org.objectweb.asm.ClassWriter -import org.objectweb.asm.tree.ClassNode +import org.objectweb.asm.commons.ClassRemapper +import org.objectweb.asm.commons.Remapper import org.objectweb.asm.util.CheckClassAdapter import java.io.BufferedInputStream import java.io.FileOutputStream @@ -52,7 +54,7 @@ class HostStubGen(val options: HostStubGenOptions) { val stats = HostStubGenStats() // Load all classes. - val allClasses = loadClassStructures(options.inJar.get) + val allClasses = ClassNodes.loadClassStructures(options.inJar.get) // Dump the classes, if specified. options.inputJarDumpFile.ifSet { @@ -70,7 +72,7 @@ class HostStubGen(val options: HostStubGenOptions) { } // Build the filters. - val filter = buildFilter(errors, allClasses, options) + val (filter, policyFileRemapper) = buildFilter(errors, allClasses, options) // Transform the jar. convert( @@ -82,62 +84,24 @@ class HostStubGen(val options: HostStubGenOptions) { allClasses, errors, stats, + policyFileRemapper, + options.numShards.get, + options.shard.get, ) // Dump statistics, if specified. options.statsFile.ifSet { - PrintWriter(it).use { pw -> stats.dump(pw) } + PrintWriter(it).use { pw -> stats.dumpOverview(pw) } log.i("Dump file created at $it") } - } - - /** - * Load all the classes, without code. - */ - private fun loadClassStructures(inJar: String): ClassNodes { - log.i("Reading class structure from $inJar ...") - val start = System.currentTimeMillis() - - val allClasses = ClassNodes() - - log.withIndent { - ZipFile(inJar).use { inZip -> - val inEntries = inZip.entries() - - while (inEntries.hasMoreElements()) { - val entry = inEntries.nextElement() - - BufferedInputStream(inZip.getInputStream(entry)).use { bis -> - if (entry.name.endsWith(".class")) { - val cr = ClassReader(bis) - val cn = ClassNode() - cr.accept(cn, ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG - or ClassReader.SKIP_FRAMES) - if (!allClasses.addClass(cn)) { - log.w("Duplicate class found: ${cn.name}") - } - } else if (entry.name.endsWith(".dex")) { - // Seems like it's an ART jar file. We can't process it. - // It's a fatal error. - throw InvalidJarFileException( - "$inJar is not a desktop jar file. It contains a *.dex file.") - } else { - // Unknown file type. Skip. - while (bis.available() > 0) { - bis.skip((1024 * 1024).toLong()) - } - } - } - } + options.apiListFile.ifSet { + PrintWriter(it).use { pw -> + // TODO, when dumping a jar that's not framework-minus-apex.jar, we need to feed + // framework-minus-apex.jar so that we can dump inherited methods from it. + ApiDumper(pw, allClasses, null, filter).dump() } + log.i("API list file created at $it") } - if (allClasses.size == 0) { - log.w("$inJar contains no *.class files.") - } - - val end = System.currentTimeMillis() - log.i("Done reading class structure in %.1f second(s).", (end - start) / 1000.0) - return allClasses } /** @@ -148,7 +112,7 @@ class HostStubGen(val options: HostStubGenOptions) { errors: HostStubGenErrors, allClasses: ClassNodes, options: HostStubGenOptions, - ): OutputFilter { + ): Pair<OutputFilter, Remapper?> { // We build a "chain" of multiple filters here. // // The filters are build in from "inside", meaning the first filter created here is @@ -201,10 +165,14 @@ class HostStubGen(val options: HostStubGenOptions) { filter, ) + var policyFileRemapper: Remapper? = null + // Next, "text based" filter, which allows to override polices without touching // the target code. options.policyOverrideFile.ifSet { - filter = createFilterFromTextPolicyFile(it, allClasses, filter) + val (f, p) = createFilterFromTextPolicyFile(it, allClasses, filter) + filter = f + policyFileRemapper = p } // If `--intersect-stub-jar` is provided, load from these jar files too. @@ -219,7 +187,7 @@ class HostStubGen(val options: HostStubGenOptions) { // Apply the implicit filter. filter = ImplicitOutputFilter(errors, allClasses, filter) - return filter + return Pair(filter, policyFileRemapper) } /** @@ -229,7 +197,7 @@ class HostStubGen(val options: HostStubGenOptions) { val intersectingJars = mutableMapOf<String, ClassNodes>() filenames.forEach { filename -> - intersectingJars[filename] = loadClassStructures(filename) + intersectingJars[filename] = ClassNodes.loadClassStructures(filename) } return intersectingJars } @@ -246,6 +214,9 @@ class HostStubGen(val options: HostStubGenOptions) { classes: ClassNodes, errors: HostStubGenErrors, stats: HostStubGenStats, + remapper: Remapper?, + numShards: Int, + shard: Int, ) { log.i("Converting %s into [stub: %s, impl: %s] ...", inJar, outStubJar, outImplJar) log.i("ASM CheckClassAdapter is %s", if (enableChecker) "enabled" else "disabled") @@ -254,17 +225,32 @@ class HostStubGen(val options: HostStubGenOptions) { val packageRedirector = PackageRedirectRemapper(options.packageRedirects) + var itemIndex = 0 + var numItemsProcessed = 0 + var numItems = -1 // == Unknown + log.withIndent { // Open the input jar file and process each entry. ZipFile(inJar).use { inZip -> + + numItems = inZip.size() + val shardStart = numItems * shard / numShards + val shardNextStart = numItems * (shard + 1) / numShards + maybeWithZipOutputStream(outStubJar) { stubOutStream -> maybeWithZipOutputStream(outImplJar) { implOutStream -> val inEntries = inZip.entries() while (inEntries.hasMoreElements()) { val entry = inEntries.nextElement() + val inShard = (shardStart <= itemIndex) && (itemIndex < shardNextStart) + itemIndex++ + if (!inShard) { + continue + } convertSingleEntry(inZip, entry, stubOutStream, implOutStream, - filter, packageRedirector, enableChecker, classes, errors, - stats) + filter, packageRedirector, remapper, + enableChecker, classes, errors, stats) + numItemsProcessed++ } log.i("Converted all entries.") } @@ -274,7 +260,8 @@ class HostStubGen(val options: HostStubGenOptions) { } } val end = System.currentTimeMillis() - log.i("Done transforming the jar in %.1f second(s).", (end - start) / 1000.0) + log.i("Done transforming the jar in %.1f second(s). %d / %d item(s) processed.", + (end - start) / 1000.0, numItemsProcessed, numItems) } private fun <T> maybeWithZipOutputStream(filename: String?, block: (ZipOutputStream?) -> T): T { @@ -294,6 +281,7 @@ class HostStubGen(val options: HostStubGenOptions) { implOutStream: ZipOutputStream?, filter: OutputFilter, packageRedirector: PackageRedirectRemapper, + remapper: Remapper?, enableChecker: Boolean, classes: ClassNodes, errors: HostStubGenErrors, @@ -311,7 +299,7 @@ class HostStubGen(val options: HostStubGenOptions) { // If it's a class, convert it. if (name.endsWith(".class")) { processSingleClass(inZip, entry, stubOutStream, implOutStream, filter, - packageRedirector, enableChecker, classes, errors, stats) + packageRedirector, remapper, enableChecker, classes, errors, stats) return } @@ -362,6 +350,7 @@ class HostStubGen(val options: HostStubGenOptions) { implOutStream: ZipOutputStream?, filter: OutputFilter, packageRedirector: PackageRedirectRemapper, + remapper: Remapper?, enableChecker: Boolean, classes: ClassNodes, errors: HostStubGenErrors, @@ -373,16 +362,24 @@ class HostStubGen(val options: HostStubGenOptions) { log.d("Removing class: %s %s", classInternalName, classPolicy) return } + // If we're applying a remapper, we need to rename the file too. + var newName = entry.name + remapper?.mapType(classInternalName)?.let { remappedName -> + if (remappedName != classInternalName) { + log.d("Renaming class file: %s -> %s", classInternalName, remappedName) + newName = remappedName + ".class" + } + } // Generate stub first. if (stubOutStream != null && classPolicy.policy.needsInStub) { log.v("Creating stub class: %s Policy: %s", classInternalName, classPolicy) log.withIndent { BufferedInputStream(inZip.getInputStream(entry)).use { bis -> - val newEntry = ZipEntry(entry.name) + val newEntry = ZipEntry(newName) stubOutStream.putNextEntry(newEntry) convertClass(classInternalName, /*forImpl=*/false, bis, - stubOutStream, filter, packageRedirector, enableChecker, classes, - errors, null) + stubOutStream, filter, packageRedirector, remapper, + enableChecker, classes, errors, null) stubOutStream.closeEntry() } } @@ -391,11 +388,11 @@ class HostStubGen(val options: HostStubGenOptions) { log.v("Creating impl class: %s Policy: %s", classInternalName, classPolicy) log.withIndent { BufferedInputStream(inZip.getInputStream(entry)).use { bis -> - val newEntry = ZipEntry(entry.name) + val newEntry = ZipEntry(newName) implOutStream.putNextEntry(newEntry) convertClass(classInternalName, /*forImpl=*/true, bis, - implOutStream, filter, packageRedirector, enableChecker, classes, - errors, stats) + implOutStream, filter, packageRedirector, remapper, + enableChecker, classes, errors, stats) implOutStream.closeEntry() } } @@ -412,6 +409,7 @@ class HostStubGen(val options: HostStubGenOptions) { out: OutputStream, filter: OutputFilter, packageRedirector: PackageRedirectRemapper, + remapper: Remapper?, enableChecker: Boolean, classes: ClassNodes, errors: HostStubGenErrors, @@ -428,6 +426,12 @@ class HostStubGen(val options: HostStubGenOptions) { if (enableChecker) { outVisitor = CheckClassAdapter(outVisitor) } + + // Remapping should happen at the end. + remapper?.let { + outVisitor = ClassRemapper(outVisitor, remapper) + } + val visitorOptions = BaseAdapter.Options( enablePreTrace = options.enablePreTrace.get, enablePostTrace = options.enablePostTrace.get, @@ -436,7 +440,7 @@ class HostStubGen(val options: HostStubGenOptions) { stats = stats, ) outVisitor = BaseAdapter.getVisitor(classInternalName, classes, outVisitor, filter, - packageRedirector, forImpl, visitorOptions) + packageRedirector, remapper, forImpl, visitorOptions) cr.accept(outVisitor, ClassReader.EXPAND_FRAMES) val data = cw.toByteArray() diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Main.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenMain.kt index 4882c00d2b3c..45e7e301c0d1 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Main.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenMain.kt @@ -13,18 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@file:JvmName("Main") +@file:JvmName("HostStubGenMain") package com.android.hoststubgen import java.io.PrintWriter -const val COMMAND_NAME = "HostStubGen" - /** * Entry point. */ fun main(args: Array<String>) { + executableName = "HostStubGen" + var success = false var clanupOnError = false @@ -33,7 +33,7 @@ fun main(args: Array<String>) { val options = HostStubGenOptions.parseArgs(args) clanupOnError = options.cleanUpOnError.get - log.v("HostStubGen started") + log.v("$executableName started") log.v("Options: $options") // Run. @@ -41,7 +41,7 @@ fun main(args: Array<String>) { success = true } catch (e: Throwable) { - log.e("$COMMAND_NAME: Error: ${e.message}") + log.e("$executableName: Error: ${e.message}") if (e !is UserErrorException) { e.printStackTrace(PrintWriter(log.getWriter(LogLevel.Error))) } @@ -49,7 +49,7 @@ fun main(args: Array<String>) { TODO("Remove output jars here") } } finally { - log.i("$COMMAND_NAME finished") + log.i("$executableName finished") log.flush() } diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt index 9f5d524517d0..2f833a873133 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt @@ -110,6 +110,11 @@ class HostStubGenOptions( var enableNonStubMethodCallDetection: SetOnce<Boolean> = SetOnce(false), var statsFile: SetOnce<String?> = SetOnce(null), + + var apiListFile: SetOnce<String?> = SetOnce(null), + + var numShards: SetOnce<Int> = SetOnce(1), + var shard: SetOnce<Int> = SetOnce(0), ) { companion object { @@ -160,6 +165,13 @@ class HostStubGenOptions( fun SetOnce<String?>.setNextStringArg(): String = nextArg().also { this.set(it) } fun MutableSet<String>.addUniqueAnnotationArg(): String = nextArg().also { this += ensureUniqueAnnotation(it) } + fun SetOnce<Int>.setNextIntArg(): String = nextArg().also { + try { + this.set(it.toInt()) + } catch (e: NumberFormatException) { + throw ArgumentsException("Invalid integer for $arg: $it") + } + } try { when (arg) { @@ -255,6 +267,10 @@ class HostStubGenOptions( "--debug-log" -> setLogFile(LogLevel.Debug, nextArg()) "--stats-file" -> ret.statsFile.setNextStringArg() + "--supported-api-list-file" -> ret.apiListFile.setNextStringArg() + + "--num-shards" -> ret.numShards.setNextIntArg() + "--shard-index" -> ret.shard.setNextIntArg() else -> throw ArgumentsException("Unknown option: $arg") } @@ -268,7 +284,7 @@ class HostStubGenOptions( } if (!ret.outStubJar.isSet && !ret.outImplJar.isSet) { log.w("Neither --out-stub-jar nor --out-impl-jar is set." + - " $COMMAND_NAME will not generate jar files.") + " $executableName will not generate jar files.") } if (ret.enableNonStubMethodCallDetection.get) { @@ -392,6 +408,9 @@ class HostStubGenOptions( enablePostTrace=$enablePostTrace, enableNonStubMethodCallDetection=$enableNonStubMethodCallDetection, statsFile=$statsFile, + apiListFile=$apiListFile, + numShards=$numShards, + shard=$shard, } """.trimIndent() } diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt index 50518e1ccd9c..9045db210495 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt @@ -15,7 +15,8 @@ */ package com.android.hoststubgen -import com.android.hoststubgen.asm.toHumanReadableClassName +import com.android.hoststubgen.asm.getOuterClassNameFromFullClassName +import com.android.hoststubgen.asm.getPackageNameFromFullClassName import com.android.hoststubgen.filters.FilterPolicyWithReason import org.objectweb.asm.Opcodes import java.io.PrintWriter @@ -29,8 +30,25 @@ open class HostStubGenStats { private val stats = mutableMapOf<String, Stats>() - fun onVisitPolicyForMethod(fullClassName: String, methodName: String, descriptor: String, - policy: FilterPolicyWithReason, access: Int) { + data class Api( + val fullClassName: String, + val methodName: String, + val methodDesc: String, + ) + + private val apis = mutableListOf<Api>() + + fun onVisitPolicyForMethod( + fullClassName: String, + methodName: String, + descriptor: String, + policy: FilterPolicyWithReason, + access: Int + ) { + if (policy.policy.isSupported) { + apis.add(Api(fullClassName, methodName, descriptor)) + } + // Ignore methods that aren't public if ((access and Opcodes.ACC_PUBLIC) == 0) return // Ignore methods that are abstract @@ -38,8 +56,8 @@ open class HostStubGenStats { // Ignore methods where policy isn't relevant if (policy.isIgnoredForStats) return - val packageName = resolvePackageName(fullClassName) - val className = resolveClassName(fullClassName) + val packageName = getPackageNameFromFullClassName(fullClassName) + val className = getOuterClassNameFromFullClassName(fullClassName) // Ignore methods for certain generated code if (className.endsWith("Proto") @@ -60,30 +78,15 @@ open class HostStubGenStats { classStats.total += 1 } - fun dump(pw: PrintWriter) { + fun dumpOverview(pw: PrintWriter) { pw.printf("PackageName,ClassName,SupportedMethods,TotalMethods\n") - stats.forEach { (packageName, packageStats) -> + stats.toSortedMap().forEach { (packageName, packageStats) -> if (packageStats.supported > 0) { - packageStats.children.forEach { (className, classStats) -> + packageStats.children.toSortedMap().forEach { (className, classStats) -> pw.printf("%s,%s,%d,%d\n", packageName, className, classStats.supported, classStats.total) } } } } - - private fun resolvePackageName(fullClassName: String): String { - val start = fullClassName.lastIndexOf('/') - return fullClassName.substring(0, start).toHumanReadableClassName() - } - - private fun resolveClassName(fullClassName: String): String { - val start = fullClassName.lastIndexOf('/') - val end = fullClassName.indexOf('$') - if (end == -1) { - return fullClassName.substring(start + 1) - } else { - return fullClassName.substring(start + 1, end) - } - } } diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt index 937e56c2cbb5..10179eefcb95 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt @@ -16,6 +16,11 @@ package com.android.hoststubgen /** + * Name of this executable. Set it in the main method. + */ +var executableName = "[command name not set]" + +/** * A regex that maches whitespate. */ val whitespaceRegex = """\s+""".toRegex() @@ -84,3 +89,10 @@ class ParseException : Exception, UserErrorException { } } } + +/** + * Escape a string for a CSV field. + */ +fun csvEscape(value: String): String { + return "\"" + value.replace("\"", "\"\"") + "\"" +} diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt index 0579c2bb0525..3f2b13aed5c0 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt @@ -34,6 +34,9 @@ val CLASS_INITIALIZER_NAME = "<clinit>" /** Descriptor of the class initializer method. */ val CLASS_INITIALIZER_DESC = "()V" +/** Name of constructors. */ +val CTOR_NAME = "<init>" + /** * Find any of [anyAnnotations] from the list of visible / invisible annotations. */ @@ -73,17 +76,45 @@ fun findAnnotationValueAsString(an: AnnotationNode, propertyName: String): Strin return null } -private val removeLastElement = """[./][^./]*$""".toRegex() +val periodOrSlash = charArrayOf('.', '/') -fun getPackageNameFromClassName(className: String): String { - return className.replace(removeLastElement, "") +fun getPackageNameFromFullClassName(fullClassName: String): String { + val pos = fullClassName.lastIndexOfAny(periodOrSlash) + if (pos == -1) { + return "" + } else { + return fullClassName.substring(0, pos) + } +} + +fun getClassNameFromFullClassName(fullClassName: String): String { + val pos = fullClassName.lastIndexOfAny(periodOrSlash) + if (pos == -1) { + return fullClassName + } else { + return fullClassName.substring(pos + 1) + } } -fun resolveClassName(className: String, packageName: String): String { +fun getOuterClassNameFromFullClassName(fullClassName: String): String { + val start = fullClassName.lastIndexOfAny(periodOrSlash) + val end = fullClassName.indexOf('$') + if (end == -1) { + return fullClassName.substring(start + 1) + } else { + return fullClassName.substring(start + 1, end) + } +} + +/** + * If [className] is a fully qualified name, just return it. + * Otherwise, prepend [defaultPackageName]. + */ +fun resolveClassNameWithDefaultPackage(className: String, defaultPackageName: String): String { if (className.contains('.') || className.contains('/')) { return className } - return "$packageName.$className" + return "$defaultPackageName.$className" } fun String.toJvmClassName(): String { @@ -135,10 +166,10 @@ fun writeByteCodeToPushArguments( // Note, long and double will consume two local variable spaces, so the extra `i++`. when (type) { Type.VOID_TYPE -> throw HostStubGenInternalException("VOID_TYPE not expected") - Type.BOOLEAN_TYPE, Type.INT_TYPE, Type.SHORT_TYPE, Type.CHAR_TYPE + Type.BOOLEAN_TYPE, Type.CHAR_TYPE, Type.BYTE_TYPE, Type.SHORT_TYPE, Type.INT_TYPE -> writer.visitVarInsn(Opcodes.ILOAD, i) - Type.LONG_TYPE -> writer.visitVarInsn(Opcodes.LLOAD, i++) Type.FLOAT_TYPE -> writer.visitVarInsn(Opcodes.FLOAD, i) + Type.LONG_TYPE -> writer.visitVarInsn(Opcodes.LLOAD, i++) Type.DOUBLE_TYPE -> writer.visitVarInsn(Opcodes.DLOAD, i++) else -> writer.visitVarInsn(Opcodes.ALOAD, i) } @@ -154,10 +185,10 @@ fun writeByteCodeToReturn(methodDescriptor: String, writer: MethodVisitor) { // See https://en.wikipedia.org/wiki/List_of_Java_bytecode_instructions when (type) { Type.VOID_TYPE -> writer.visitInsn(Opcodes.RETURN) - Type.BOOLEAN_TYPE, Type.INT_TYPE, Type.SHORT_TYPE, Type.CHAR_TYPE + Type.BOOLEAN_TYPE, Type.CHAR_TYPE, Type.BYTE_TYPE, Type.SHORT_TYPE, Type.INT_TYPE -> writer.visitInsn(Opcodes.IRETURN) - Type.LONG_TYPE -> writer.visitInsn(Opcodes.LRETURN) Type.FLOAT_TYPE -> writer.visitInsn(Opcodes.FRETURN) + Type.LONG_TYPE -> writer.visitInsn(Opcodes.LRETURN) Type.DOUBLE_TYPE -> writer.visitInsn(Opcodes.DRETURN) else -> writer.visitInsn(Opcodes.ARETURN) } @@ -259,6 +290,16 @@ fun FieldNode.getVisibility(): Visibility { return Visibility.fromAccess(this.access) } +/** Return the [access] flags without the visibility */ +fun clearVisibility(access: Int): Int { + return access and (Opcodes.ACC_PUBLIC or Opcodes.ACC_PROTECTED or Opcodes.ACC_PRIVATE).inv() +} + +/** Return the visibility part of the [access] flags */ +fun getVisibility(access: Int): Int { + return access and (Opcodes.ACC_PUBLIC or Opcodes.ACC_PROTECTED or Opcodes.ACC_PRIVATE) +} + /* diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt index bc34ef0dc8a7..92906a75b93a 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt @@ -16,13 +16,18 @@ package com.android.hoststubgen.asm import com.android.hoststubgen.ClassParseException +import com.android.hoststubgen.InvalidJarFileException +import com.android.hoststubgen.log +import org.objectweb.asm.ClassReader import org.objectweb.asm.tree.AnnotationNode import org.objectweb.asm.tree.ClassNode import org.objectweb.asm.tree.FieldNode import org.objectweb.asm.tree.MethodNode import org.objectweb.asm.tree.TypeAnnotationNode +import java.io.BufferedInputStream import java.io.PrintWriter import java.util.Arrays +import java.util.zip.ZipFile /** * Stores all classes loaded from a jar file, in a form of [ClassNode] @@ -62,8 +67,8 @@ class ClassNodes { /** Find a field, which may not exist. */ fun findField( - className: String, - fieldName: String, + className: String, + fieldName: String, ): FieldNode? { return findClass(className)?.fields?.firstOrNull { it.name == fieldName }?.let { fn -> return fn @@ -72,14 +77,14 @@ class ClassNodes { /** Find a method, which may not exist. */ fun findMethod( - className: String, - methodName: String, - descriptor: String, + className: String, + methodName: String, + descriptor: String, ): MethodNode? { return findClass(className)?.methods - ?.firstOrNull { it.name == methodName && it.desc == descriptor }?.let { mn -> - return mn - } + ?.firstOrNull { it.name == methodName && it.desc == descriptor }?.let { mn -> + return mn + } } /** @return true if a class has a class initializer. */ @@ -106,26 +111,33 @@ class ClassNodes { private fun dumpClass(pw: PrintWriter, cn: ClassNode) { pw.printf("Class: %s [access: %x]\n", cn.name, cn.access) - dumpAnnotations(pw, " ", - cn.visibleTypeAnnotations, cn.invisibleTypeAnnotations, - cn.visibleAnnotations, cn.invisibleAnnotations, - ) + dumpAnnotations( + pw, " ", + cn.visibleTypeAnnotations, cn.invisibleTypeAnnotations, + cn.visibleAnnotations, cn.invisibleAnnotations, + ) for (f in cn.fields ?: emptyList()) { - pw.printf(" Field: %s [sig: %s] [desc: %s] [access: %x]\n", - f.name, f.signature, f.desc, f.access) - dumpAnnotations(pw, " ", - f.visibleTypeAnnotations, f.invisibleTypeAnnotations, - f.visibleAnnotations, f.invisibleAnnotations, - ) + pw.printf( + " Field: %s [sig: %s] [desc: %s] [access: %x]\n", + f.name, f.signature, f.desc, f.access + ) + dumpAnnotations( + pw, " ", + f.visibleTypeAnnotations, f.invisibleTypeAnnotations, + f.visibleAnnotations, f.invisibleAnnotations, + ) } for (m in cn.methods ?: emptyList()) { - pw.printf(" Method: %s [sig: %s] [desc: %s] [access: %x]\n", - m.name, m.signature, m.desc, m.access) - dumpAnnotations(pw, " ", - m.visibleTypeAnnotations, m.invisibleTypeAnnotations, - m.visibleAnnotations, m.invisibleAnnotations, - ) + pw.printf( + " Method: %s [sig: %s] [desc: %s] [access: %x]\n", + m.name, m.signature, m.desc, m.access + ) + dumpAnnotations( + pw, " ", + m.visibleTypeAnnotations, m.invisibleTypeAnnotations, + m.visibleAnnotations, m.invisibleAnnotations, + ) } } @@ -136,7 +148,7 @@ class ClassNodes { invisibleTypeAnnotations: List<TypeAnnotationNode>?, visibleAnnotations: List<AnnotationNode>?, invisibleAnnotations: List<AnnotationNode>?, - ) { + ) { for (an in visibleTypeAnnotations ?: emptyList()) { pw.printf("%sTypeAnnotation(vis): %s\n", prefix, an.desc) } @@ -166,4 +178,55 @@ class ClassNodes { } } } + + companion object { + /** + * Load all the classes, without code. + */ + fun loadClassStructures(inJar: String): ClassNodes { + log.i("Reading class structure from $inJar ...") + val start = System.currentTimeMillis() + + val allClasses = ClassNodes() + + log.withIndent { + ZipFile(inJar).use { inZip -> + val inEntries = inZip.entries() + + while (inEntries.hasMoreElements()) { + val entry = inEntries.nextElement() + + BufferedInputStream(inZip.getInputStream(entry)).use { bis -> + if (entry.name.endsWith(".class")) { + val cr = ClassReader(bis) + val cn = ClassNode() + cr.accept(cn, ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG + or ClassReader.SKIP_FRAMES) + if (!allClasses.addClass(cn)) { + log.w("Duplicate class found: ${cn.name}") + } + } else if (entry.name.endsWith(".dex")) { + // Seems like it's an ART jar file. We can't process it. + // It's a fatal error. + throw InvalidJarFileException( + "$inJar is not a desktop jar file. It contains a *.dex file.") + } else { + // Unknown file type. Skip. + while (bis.available() > 0) { + bis.skip((1024 * 1024).toLong()) + } + } + } + } + } + } + if (allClasses.size == 0) { + log.w("$inJar contains no *.class files.") + } + + val end = System.currentTimeMillis() + log.i("Done reading class structure in %.1f second(s).", (end - start) / 1000.0) + return allClasses + } + } }
\ No newline at end of file diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/dumper/ApiDumper.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/dumper/ApiDumper.kt new file mode 100644 index 000000000000..aaefee4f71e8 --- /dev/null +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/dumper/ApiDumper.kt @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2024 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.hoststubgen.dumper + +import com.android.hoststubgen.asm.CLASS_INITIALIZER_NAME +import com.android.hoststubgen.asm.CTOR_NAME +import com.android.hoststubgen.asm.ClassNodes +import com.android.hoststubgen.asm.getClassNameFromFullClassName +import com.android.hoststubgen.asm.getPackageNameFromFullClassName +import com.android.hoststubgen.asm.toHumanReadableClassName +import com.android.hoststubgen.csvEscape +import com.android.hoststubgen.filters.FilterPolicy +import com.android.hoststubgen.filters.FilterPolicyWithReason +import com.android.hoststubgen.filters.OutputFilter +import com.android.hoststubgen.log +import org.objectweb.asm.Type +import org.objectweb.asm.tree.ClassNode +import java.io.PrintWriter + +/** + * Dump all the API methods in [classes], with inherited methods, with their policies. + */ +class ApiDumper( + val pw: PrintWriter, + val classes: ClassNodes, + val frameworkClasses: ClassNodes?, + val filter: OutputFilter, +) { + private data class MethodKey( + val name: String, + val descriptor: String, + ) + + val javaStandardApiPolicy = FilterPolicy.Stub.withReason("Java standard API") + + private val shownMethods = mutableSetOf<MethodKey>() + + /** + * Do the dump. + */ + fun dump() { + pw.printf("PackageName,ClassName,FromSubclass,DeclareClass,MethodName,MethodDesc" + + ",Supported,Policy,Reason\n") + + classes.forEach { classNode -> + shownMethods.clear() + dump(classNode, classNode) + } + } + + private fun dumpMethod( + classPackage: String, + className: String, + isSuperClass: Boolean, + methodClassName: String, + methodName: String, + methodDesc: String, + policy: FilterPolicyWithReason, + ) { + pw.printf( + "%s,%s,%d,%s,%s,%s,%d,%s,%s\n", + csvEscape(classPackage), + csvEscape(className), + if (isSuperClass) { 1 } else { 0 }, + csvEscape(methodClassName), + csvEscape(methodName), + csvEscape(methodDesc), + if (policy.policy.isSupported) { 1 } else { 0 }, + policy.policy, + csvEscape(policy.reason), + ) + } + + private fun isDuplicate(methodName: String, methodDesc: String): Boolean { + val methodKey = MethodKey(methodName, methodDesc) + + if (shownMethods.contains(methodKey)) { + return true + } + shownMethods.add(methodKey) + return false + } + + private fun dump( + dumpClass: ClassNode, + methodClass: ClassNode, + ) { + val pkg = getPackageNameFromFullClassName(dumpClass.name).toHumanReadableClassName() + val cls = getClassNameFromFullClassName(dumpClass.name).toHumanReadableClassName() + + val isSuperClass = dumpClass != methodClass + + methodClass.methods?.sortedWith(compareBy({ it.name }, { it.desc }))?.forEach { method -> + + // Don't print ctor's from super classes. + if (isSuperClass) { + if (CTOR_NAME == method.name || CLASS_INITIALIZER_NAME == method.name) { + return@forEach + } + } + // If we already printed the method from a subclass, don't print it. + if (isDuplicate(method.name, method.desc)) { + return@forEach + } + + val policy = filter.getPolicyForMethod(methodClass.name, method.name, method.desc) + + // Let's skip "Remove" APIs. Ideally we want to print it, just to make the CSV + // complete, we still need to hide methods substituted (== @RavenwoodReplace) methods + // and for now we don't have an easy way to detect it. + if (policy.policy == FilterPolicy.Remove) { + return@forEach + } + + val renameTo = filter.getRenameTo(methodClass.name, method.name, method.desc) + + dumpMethod(pkg, cls, isSuperClass, methodClass.name.toHumanReadableClassName(), + renameTo ?: method.name, method.desc, policy) + } + + // Dump super class methods. + dumpSuper(dumpClass, methodClass.superName) + + // Dump interface methods (which may have default methods). + methodClass.interfaces?.sorted()?.forEach { interfaceName -> + dumpSuper(dumpClass, interfaceName) + } + } + + /** + * Dump a given super class / interface. + */ + private fun dumpSuper( + dumpClass: ClassNode, + methodClassName: String, + ) { + classes.findClass(methodClassName)?.let { methodClass -> + dump(dumpClass, methodClass) + return + } + frameworkClasses?.findClass(methodClassName)?.let { methodClass -> + dump(dumpClass, methodClass) + return + } + if (methodClassName.startsWith("java/") || + methodClassName.startsWith("javax/") + ) { + dumpStandardClass(dumpClass, methodClassName) + return + } + log.w("Super class or interface $methodClassName (used by ${dumpClass.name}) not found.") + } + + /** + * Dump methods from Java standard classes. + */ + private fun dumpStandardClass( + dumpClass: ClassNode, + methodClassName: String, + ) { + val pkg = getPackageNameFromFullClassName(dumpClass.name).toHumanReadableClassName() + val cls = getClassNameFromFullClassName(dumpClass.name).toHumanReadableClassName() + + val methodClassName = methodClassName.toHumanReadableClassName() + + try { + val clazz = Class.forName(methodClassName) + + // Method.getMethods() returns only public methods, but with inherited ones. + // Method.getDeclaredMethods() returns private methods too, but no inherited methods. + // + // Since we're only interested in public ones, just use getMethods(). + clazz.methods.forEach { method -> + val methodName = method.name + val methodDesc = Type.getMethodDescriptor(method) + + // If we already printed the method from a subclass, don't print it. + if (isDuplicate(methodName, methodDesc)) { + return@forEach + } + + dumpMethod(pkg, cls, true, methodClassName, + methodName, methodDesc, javaStandardApiPolicy) + } + } catch (e: ClassNotFoundException) { + log.w("JVM type $methodClassName (used by ${dumpClass.name}) not found.") + } + } +} diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt index 16785d1d9598..6b360b79c327 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt @@ -25,6 +25,7 @@ class AndroidHeuristicsFilter( val aidlPolicy: FilterPolicyWithReason?, val featureFlagsPolicy: FilterPolicyWithReason?, val syspropsPolicy: FilterPolicyWithReason?, + val rFilePolicy: FilterPolicyWithReason?, fallback: OutputFilter ) : DelegatingFilter(fallback) { override fun getPolicyForClass(className: String): FilterPolicyWithReason { @@ -37,6 +38,9 @@ class AndroidHeuristicsFilter( if (syspropsPolicy != null && classes.isSyspropsClass(className)) { return syspropsPolicy } + if (rFilePolicy != null && classes.isRClass(className)) { + return rFilePolicy + } return super.getPolicyForClass(className) } } @@ -74,3 +78,10 @@ private fun ClassNodes.isSyspropsClass(className: String): Boolean { return className.startsWith("android/sysprop/") && className.endsWith("Properties") } + +/** + * @return if a given class "seems like" an R class or its nested classes. + */ +private fun ClassNodes.isRClass(className: String): Boolean { + return className.endsWith("/R") || className.contains("/R$") +} diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt index 78b13fd36f06..5a26fc69d473 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt @@ -19,14 +19,14 @@ import com.android.hoststubgen.HostStubGenErrors import com.android.hoststubgen.HostStubGenInternalException import com.android.hoststubgen.asm.CLASS_INITIALIZER_DESC import com.android.hoststubgen.asm.CLASS_INITIALIZER_NAME -import com.android.hoststubgen.asm.isAnonymousInnerClass -import com.android.hoststubgen.log import com.android.hoststubgen.asm.ClassNodes import com.android.hoststubgen.asm.isAnnotation +import com.android.hoststubgen.asm.isAnonymousInnerClass import com.android.hoststubgen.asm.isAutoGeneratedEnumMember import com.android.hoststubgen.asm.isEnum import com.android.hoststubgen.asm.isSynthetic import com.android.hoststubgen.asm.isVisibilityPrivateOrPackagePrivate +import com.android.hoststubgen.log import org.objectweb.asm.tree.ClassNode /** diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt index 5659a35170c1..2e144f5513bc 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt @@ -15,11 +15,11 @@ */ package com.android.hoststubgen.filters -import com.android.hoststubgen.UnknownApiException import com.android.hoststubgen.addNonNullElement import com.android.hoststubgen.asm.ClassNodes import com.android.hoststubgen.asm.toHumanReadableClassName import com.android.hoststubgen.asm.toHumanReadableMethodName +import com.android.hoststubgen.log // TODO: Validate all input names. @@ -48,30 +48,30 @@ class InMemoryOutputFilter( return mPolicies[getClassKey(className)] ?: super.getPolicyForClass(className) } - private fun ensureClassExists(className: String) { + private fun checkClass(className: String) { if (classes.findClass(className) == null) { - throw UnknownApiException("Unknown class $className") + log.w("Unknown class $className") } } - private fun ensureFieldExists(className: String, fieldName: String) { + private fun checkField(className: String, fieldName: String) { if (classes.findField(className, fieldName) == null) { - throw UnknownApiException("Unknown field $className.$fieldName") + log.w("Unknown field $className.$fieldName") } } - private fun ensureMethodExists( + private fun checkMethod( className: String, methodName: String, descriptor: String ) { if (classes.findMethod(className, methodName, descriptor) == null) { - throw UnknownApiException("Unknown method $className.$methodName$descriptor") + log.w("Unknown method $className.$methodName$descriptor") } } fun setPolicyForClass(className: String, policy: FilterPolicyWithReason) { - ensureClassExists(className) + checkClass(className) mPolicies[getClassKey(className)] = policy } @@ -81,7 +81,7 @@ class InMemoryOutputFilter( } fun setPolicyForField(className: String, fieldName: String, policy: FilterPolicyWithReason) { - ensureFieldExists(className, fieldName) + checkField(className, fieldName) mPolicies[getFieldKey(className, fieldName)] = policy } @@ -100,7 +100,7 @@ class InMemoryOutputFilter( descriptor: String, policy: FilterPolicyWithReason, ) { - ensureMethodExists(className, methodName, descriptor) + checkMethod(className, methodName, descriptor) mPolicies[getMethodKey(className, methodName, descriptor)] = policy } @@ -110,8 +110,8 @@ class InMemoryOutputFilter( } fun setRenameTo(className: String, methodName: String, descriptor: String, toName: String) { - ensureMethodExists(className, methodName, descriptor) - ensureMethodExists(className, toName, descriptor) + checkMethod(className, methodName, descriptor) + checkMethod(className, toName, descriptor) mRenames[getMethodKey(className, methodName, descriptor)] = toName } @@ -121,7 +121,7 @@ class InMemoryOutputFilter( } fun setNativeSubstitutionClass(from: String, to: String) { - ensureClassExists(from) + checkClass(from) // Native substitute classes may be provided from other jars, so we can't do this check. // ensureClassExists(to) diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/PackageFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/PackageFilter.kt new file mode 100644 index 000000000000..c67e6714d4c2 --- /dev/null +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/PackageFilter.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2024 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.hoststubgen.filters + +import com.android.hoststubgen.asm.toHumanReadableClassName +import com.android.hoststubgen.utils.Trie + +/** + * Filter to apply a policy to classes inside a package, either directly or indirectly. + */ +class PackageFilter( + fallback: OutputFilter +) : DelegatingFilter(fallback) { + + private val mPackagePolicies = PackagePolicyTrie() + + // We want to pick the most specific filter for a package name. + // Since any package with a matching prefix is a valid match, we can use a prefix tree + // to help us find the nearest matching filter. + private class PackagePolicyTrie : Trie<String, String, FilterPolicyWithReason>() { + // Split package name into individual component + override fun splitToComponents(key: String): Iterator<String> { + return key.split('.').iterator() + } + } + + private fun getPackageKey(packageName: String): String { + return packageName.toHumanReadableClassName() + } + + private fun getPackageKeyFromClass(className: String): String { + val clazz = className.toHumanReadableClassName() + val idx = clazz.lastIndexOf('.') + return if (idx >= 0) clazz.substring(0, idx) else "" + } + + /** + * Add a policy to all classes inside a package, either directly or indirectly. + */ + fun addPolicy(packageName: String, policy: FilterPolicyWithReason) { + mPackagePolicies[getPackageKey(packageName)] = policy + } + + override fun getPolicyForClass(className: String): FilterPolicyWithReason { + return mPackagePolicies[getPackageKeyFromClass(className)] + ?: super.getPolicyForClass(className) + } +} diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt index 75b5fc8f77ea..18280034c2f4 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt @@ -17,27 +17,34 @@ package com.android.hoststubgen.filters import com.android.hoststubgen.ParseException import com.android.hoststubgen.asm.ClassNodes +import com.android.hoststubgen.asm.toHumanReadableClassName import com.android.hoststubgen.log import com.android.hoststubgen.normalizeTextLine import com.android.hoststubgen.whitespaceRegex import org.objectweb.asm.Opcodes +import org.objectweb.asm.commons.Remapper import org.objectweb.asm.tree.ClassNode import java.io.BufferedReader import java.io.FileReader import java.io.PrintWriter import java.util.Objects +import java.util.regex.Pattern /** * Print a class node as a "keep" policy. */ fun printAsTextPolicy(pw: PrintWriter, cn: ClassNode) { - pw.printf("class %s\t%s\n", cn.name, "keep") + pw.printf("class %s %s\n", cn.name.toHumanReadableClassName(), "keep") - for (f in cn.fields ?: emptyList()) { - pw.printf(" field %s\t%s\n", f.name, "keep") + cn.fields?.let { + for (f in it.sortedWith(compareBy({ it.name }))) { + pw.printf(" field %s %s\n", f.name, "keep") + } } - for (m in cn.methods ?: emptyList()) { - pw.printf(" method %s\t%s\t%s\n", m.name, m.desc, "keep") + cn.methods?.let { + for (m in it.sortedWith(compareBy({ it.name }, { it.desc }))) { + pw.printf(" method %s %s %s\n", m.name, m.desc, "keep") + } } } @@ -55,27 +62,27 @@ fun createFilterFromTextPolicyFile( filename: String, classes: ClassNodes, fallback: OutputFilter, - ): OutputFilter { + ): Pair<OutputFilter, Remapper?> { log.i("Loading offloaded annotations from $filename ...") log.withIndent { val subclassFilter = SubclassFilter(classes, fallback) - val imf = InMemoryOutputFilter(classes, subclassFilter) + val packageFilter = PackageFilter(subclassFilter) + val imf = InMemoryOutputFilter(classes, packageFilter) var lineNo = 0 var aidlPolicy: FilterPolicyWithReason? = null var featureFlagsPolicy: FilterPolicyWithReason? = null var syspropsPolicy: FilterPolicyWithReason? = null + var rFilePolicy: FilterPolicyWithReason? = null + val typeRenameSpec = mutableListOf<TextFilePolicyRemapper.TypeRenameSpec>() try { BufferedReader(FileReader(filename)).use { reader -> var className = "" while (true) { - var line = reader.readLine() - if (line == null) { - break - } + var line = reader.readLine() ?: break lineNo++ line = normalizeTextLine(line) @@ -89,6 +96,31 @@ fun createFilterFromTextPolicyFile( val fields = line.split(whitespaceRegex).toTypedArray() when (fields[0].lowercase()) { + "p", "package" -> { + if (fields.size < 3) { + throw ParseException("Package ('p') expects 2 fields.") + } + val name = fields[1] + val rawPolicy = fields[2] + if (resolveExtendingClass(name) != null) { + throw ParseException("Package can't be a super class type") + } + if (resolveSpecialClass(name) != SpecialClass.NotSpecial) { + throw ParseException("Package can't be a special class type") + } + if (rawPolicy.startsWith("!")) { + throw ParseException("Package can't have a substitution") + } + if (rawPolicy.startsWith("~")) { + throw ParseException("Package can't have a class load hook") + } + val policy = parsePolicy(rawPolicy) + if (!policy.isUsableWithClasses) { + throw ParseException("Package can't have policy '$policy'") + } + packageFilter.addPolicy(name, policy.withReason(FILTER_REASON)) + } + "c", "class" -> { if (fields.size < 3) { throw ParseException("Class ('c') expects 2 fields.") @@ -162,6 +194,14 @@ fun createFilterFromTextPolicyFile( syspropsPolicy = policy.withReason( "$FILTER_REASON (special-class sysprops)") } + SpecialClass.RFile -> { + if (rFilePolicy != null) { + throw ParseException( + "Policy for R file already defined") + } + rFilePolicy = policy.withReason( + "$FILTER_REASON (special-class R file)") + } } } } @@ -214,6 +254,22 @@ fun createFilterFromTextPolicyFile( imf.setRenameTo(className, fromName, signature, name) } } + "r", "rename" -> { + if (fields.size < 3) { + throw ParseException("Rename ('r') expects 2 fields.") + } + // Add ".*" to make it a prefix match. + val pattern = Pattern.compile(fields[1] + ".*") + + // Removing the leading /'s from the prefix. This allows + // using a single '/' as an empty suffix, which is useful to have a + // "negative" rename rule to avoid subsequent raname's from getting + // applied. (Which is needed for services.jar) + val prefix = fields[2].trimStart('/') + + typeRenameSpec += TextFilePolicyRemapper.TypeRenameSpec( + pattern, prefix) + } else -> { throw ParseException("Unknown directive \"${fields[0]}\"") @@ -225,13 +281,16 @@ fun createFilterFromTextPolicyFile( throw e.withSourceInfo(filename, lineNo) } - var ret: OutputFilter = imf - if (aidlPolicy != null || featureFlagsPolicy != null || syspropsPolicy != null) { - log.d("AndroidHeuristicsFilter enabled") - ret = AndroidHeuristicsFilter( - classes, aidlPolicy, featureFlagsPolicy, syspropsPolicy, imf) + var remapper: TextFilePolicyRemapper? = null + if (typeRenameSpec.isNotEmpty()) { + remapper = TextFilePolicyRemapper(typeRenameSpec) } - return ret + + // Wrap the in-memory-filter with AHF. + return Pair( + AndroidHeuristicsFilter( + classes, aidlPolicy, featureFlagsPolicy, syspropsPolicy, rFilePolicy, imf), + remapper) } } @@ -240,6 +299,7 @@ private enum class SpecialClass { Aidl, FeatureFlags, Sysprops, + RFile, } private fun resolveSpecialClass(className: String): SpecialClass { @@ -250,6 +310,7 @@ private fun resolveSpecialClass(className: String): SpecialClass { ":aidl" -> return SpecialClass.Aidl ":feature_flags" -> return SpecialClass.FeatureFlags ":sysprops" -> return SpecialClass.Sysprops + ":r" -> return SpecialClass.RFile } throw ParseException("Invalid special class name \"$className\"") } diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapper.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapper.kt new file mode 100644 index 000000000000..2d94bb4758ba --- /dev/null +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapper.kt @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2024 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.hoststubgen.filters + +import com.android.hoststubgen.log +import org.objectweb.asm.commons.Remapper +import java.util.regex.Pattern + +/** + * A [Remapper] that provides a simple "jarjar" functionality. + */ +class TextFilePolicyRemapper( + val typeRenameSpecs: List<TypeRenameSpec> +) : Remapper() { + /** + * When a package name matches [typeInternalNamePattern], we prepend [typeInternalNamePrefix] + * to it. + */ + data class TypeRenameSpec( + val typeInternalNamePattern: Pattern, + val typeInternalNamePrefix: String, + ) + + private val cache = mutableMapOf<String, String>() + + override fun mapType(typeInternalName: String): String { +// if (typeInternalName == null) { +// return null // do we need it?? +// } + cache[typeInternalName]?.let { + return it + } + + var mapped: String = typeInternalName + typeRenameSpecs.forEach { + if (it.typeInternalNamePattern.matcher(typeInternalName).matches()) { + mapped = it.typeInternalNamePrefix + typeInternalName + log.d("Renaming type $typeInternalName to $mapped") + } + } + cache[typeInternalName] = mapped + return mapped + } + + // TODO Do we need to implement mapPackage(), etc too? +} diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/Trie.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/Trie.kt new file mode 100644 index 000000000000..1b3d79cddb8e --- /dev/null +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/Trie.kt @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2024 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.hoststubgen.utils + +abstract class Trie<Key, Component, Value> { + + private val root = TrieNode<Component, Value>() + + abstract fun splitToComponents(key: Key): Iterator<Component> + + operator fun set(key: Key, value: Value) { + val node = root.getExactNode(splitToComponents(key)) + node.value = value + } + + operator fun get(key: Key): Value? { + return root.getNearestValue(null, splitToComponents(key)) + } + + private class TrieNode<Component, Value> { + private val children = mutableMapOf<Component, TrieNode<Component, Value>>() + var value: Value? = null + + fun getExactNode(components: Iterator<Component>): TrieNode<Component, Value> { + val n = components.next() + val child = children.getOrPut(n) { TrieNode() } + return if (components.hasNext()) { + child.getExactNode(components) + } else { + child + } + } + + fun getNearestValue(current: Value?, components: Iterator<Component>): Value? { + val n = components.next() + val child = children[n] ?: return current + val newValue = child.value ?: current + return if (components.hasNext()) { + child.getNearestValue(newValue, components) + } else { + newValue + } + } + } +} diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt index 45e140c8e3ff..bad0449f1efd 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt @@ -20,8 +20,8 @@ import com.android.hoststubgen.HostStubGenStats import com.android.hoststubgen.LogLevel import com.android.hoststubgen.asm.ClassNodes import com.android.hoststubgen.asm.UnifiedVisitor -import com.android.hoststubgen.asm.getPackageNameFromClassName -import com.android.hoststubgen.asm.resolveClassName +import com.android.hoststubgen.asm.getPackageNameFromFullClassName +import com.android.hoststubgen.asm.resolveClassNameWithDefaultPackage import com.android.hoststubgen.asm.toJvmClassName import com.android.hoststubgen.filters.FilterPolicy import com.android.hoststubgen.filters.FilterPolicyWithReason @@ -34,6 +34,7 @@ import org.objectweb.asm.FieldVisitor import org.objectweb.asm.MethodVisitor import org.objectweb.asm.Opcodes import org.objectweb.asm.commons.ClassRemapper +import org.objectweb.asm.commons.Remapper import org.objectweb.asm.util.TraceClassVisitor import java.io.PrintWriter @@ -89,7 +90,7 @@ abstract class BaseAdapter ( ) { super.visit(version, access, name, signature, superName, interfaces) currentClassName = name - currentPackageName = getPackageNameFromClassName(name) + currentPackageName = getPackageNameFromFullClassName(name) classPolicy = filter.getPolicyForClass(currentClassName) log.d("[%s] visit: %s (package: %s)", this.javaClass.simpleName, name, currentPackageName) @@ -98,7 +99,8 @@ abstract class BaseAdapter ( log.indent() filter.getNativeSubstitutionClass(currentClassName)?.let { className -> - val fullClassName = resolveClassName(className, currentPackageName).toJvmClassName() + val fullClassName = resolveClassNameWithDefaultPackage(className, currentPackageName) + .toJvmClassName() log.d(" NativeSubstitutionClass: $fullClassName") if (classes.findClass(fullClassName) == null) { log.w("Native substitution class $fullClassName not found. Class must be " + @@ -194,6 +196,8 @@ abstract class BaseAdapter ( return null } + var newAccess = access + // Maybe rename the method. val newName: String val renameTo = filter.getRenameTo(currentClassName, name, descriptor) @@ -204,8 +208,9 @@ abstract class BaseAdapter ( // (the one with the @substitute/replace annotation). // `name` is the name of the method we're currently visiting, so it's usually a // "...$ravewnwood" name. - if (!checkSubstitutionMethodCompatibility( - classes, currentClassName, newName, name, descriptor, options.errors)) { + newAccess = checkSubstitutionMethodCompatibility( + classes, currentClassName, newName, name, descriptor, options.errors) + if (newAccess == NOT_COMPATIBLE) { return null } @@ -220,7 +225,7 @@ abstract class BaseAdapter ( // But note, we only use it when calling the super's method, // but not for visitMethodInner(), because when subclass wants to change access, // it can do so inside visitMethodInner(). - val newAccess = updateAccessFlags(access, name, descriptor) + newAccess = updateAccessFlags(newAccess, name, descriptor) val ret = visitMethodInner(access, newName, descriptor, signature, exceptions, policy, renameTo != null, @@ -255,13 +260,14 @@ abstract class BaseAdapter ( companion object { fun getVisitor( - classInternalName: String, - classes: ClassNodes, - nextVisitor: ClassVisitor, - filter: OutputFilter, - packageRedirector: PackageRedirectRemapper, - forImpl: Boolean, - options: Options, + classInternalName: String, + classes: ClassNodes, + nextVisitor: ClassVisitor, + filter: OutputFilter, + packageRedirector: PackageRedirectRemapper, + remapper: Remapper?, + forImpl: Boolean, + options: Options, ): ClassVisitor { var next = nextVisitor @@ -302,4 +308,4 @@ abstract class BaseAdapter ( return ret } } -}
\ No newline at end of file +} diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt index 9d66c32e76ee..dc4f26bdda34 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt @@ -17,12 +17,19 @@ package com.android.hoststubgen.visitors import com.android.hoststubgen.HostStubGenErrors import com.android.hoststubgen.asm.ClassNodes +import com.android.hoststubgen.asm.clearVisibility import com.android.hoststubgen.asm.getVisibility import com.android.hoststubgen.asm.isStatic +const val NOT_COMPATIBLE: Int = -1 + /** * Make sure substitution from and to methods have matching definition. - * (static-ness, visibility.) + * (static-ness, etc) + * + * If the methods are compatible, return the "merged" [access] of the new method. + * + * If they are not compatible, returns [NOT_COMPATIBLE] */ fun checkSubstitutionMethodCompatibility( classes: ClassNodes, @@ -31,33 +38,31 @@ fun checkSubstitutionMethodCompatibility( toMethodName: String, // the one with either a "_host" or "$ravenwood" prefix. (typically) descriptor: String, errors: HostStubGenErrors, -): Boolean { +): Int { val from = classes.findMethod(className, fromMethodName, descriptor) if (from == null) { errors.onErrorFound( - "Substitution-from method not found: $className.$fromMethodName$descriptor") - return false + "Substitution-from method not found: $className.$fromMethodName$descriptor" + ) + return NOT_COMPATIBLE } val to = classes.findMethod(className, toMethodName, descriptor) if (to == null) { // This shouldn't happen, because the visitor visited this method... errors.onErrorFound( - "Substitution-to method not found: $className.$toMethodName$descriptor") - return false + "Substitution-to method not found: $className.$toMethodName$descriptor" + ) + return NOT_COMPATIBLE } if (from.isStatic() != to.isStatic()) { errors.onErrorFound( "Substitution method must have matching static-ness: " + - "$className.$fromMethodName$descriptor") - return false - } - if (from.getVisibility().ordinal > to.getVisibility().ordinal) { - errors.onErrorFound( - "Substitution method cannot have smaller visibility than original: " + - "$className.$fromMethodName$descriptor") - return false + "$className.$fromMethodName$descriptor" + ) + return NOT_COMPATIBLE } - return true + // Return the substitution's access flag but with the original method's visibility. + return clearVisibility (to.access) or getVisibility(from.access) } diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt index b3790e12a111..e90ecd7ef678 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt @@ -20,6 +20,18 @@ import org.objectweb.asm.commons.Remapper /** * A [Remapper] for `--package-redirect` + * + * This is a feature to update all calls to specific packages to another package, which allows + * implementing a class in a different package, when the original package isn't allowed to modify. + * + * For example, using this, we can implement `dalvik.*` APIs in a separate package, and update + * all calls to the `dalvik` package to a different package. + * + * For this purpose, we don't expect the "renamed-from" classes to be in the target jar, + * so we don't apply the remapper to them. (The exclusion happens at the callsite of this class) + * + * TODO: Currently it's not used. Maybe remove, or just unify with the other remapper feature + * with TextFileFilterPolicyParser.kt. */ class PackageRedirectRemapper( packageRedirects: List<Pair<String, String>>, diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt index f70a17d9b7cd..c127e677f84d 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt @@ -322,6 +322,78 @@ NestMembers: InnerClasses: public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub +## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R$Nested + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 3 + public static int[] ARRAY; + descriptor: [I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + + public com.android.hoststubgen.test.tinyframework.R$Nested(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=1, locals=1, args_size=1 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/R$Nested; + + static {}; + descriptor: ()V + flags: (0x0008) ACC_STATIC + Code: + stack=4, locals=0, args_size=0 + x: iconst_1 + x: newarray int + x: dup + x: iconst_0 + x: iconst_1 + x: iastore + x: putstatic #x // Field ARRAY:[I + x: return + LineNumberTable: +} +SourceFile: "R.java" +NestHost: class com/android/hoststubgen/test/tinyframework/R +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R +## Class: com/android/hoststubgen/test/tinyframework/R.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 1, attributes: 3 + public com.android.hoststubgen.test.tinyframework.R(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=1, locals=1, args_size=1 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/R; +} +SourceFile: "R.java" +NestMembers: + com/android/hoststubgen/test/tinyframework/R$Nested +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class Compiled from "TinyFrameworkCallerCheck.java" class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl @@ -572,9 +644,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota suffix="_host" ) - public static int nativeAddThree_host(int); + private static int nativeAddThree_host(int); descriptor: (I)I - flags: (0x0009) ACC_PUBLIC, ACC_STATIC + flags: (0x000a) ACC_PRIVATE, ACC_STATIC Code: stack=2, locals=1, args_size=1 x: iload_0 @@ -1833,7 +1905,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative super_class: #x // java/lang/Object - interfaces: 0, fields: 1, methods: 10, attributes: 2 + interfaces: 0, fields: 1, methods: 11, attributes: 2 int value; descriptor: I flags: (0x0000) @@ -1938,6 +2010,10 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V x: athrow LineNumberTable: + + public static native byte nativeBytePlus(byte, byte); + descriptor: (BB)B + flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE } SourceFile: "TinyFrameworkNative.java" RuntimeInvisibleAnnotations: @@ -1955,7 +2031,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 4, attributes: 2 + interfaces: 0, fields: 0, methods: 5, attributes: 2 public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -2013,6 +2089,22 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host Start Length Slot Name Signature 0 7 0 source Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative; 0 7 1 arg I + + public static byte nativeBytePlus(byte, byte); + descriptor: (BB)B + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=2, locals=2, args_size=2 + x: iload_0 + x: iload_1 + x: iadd + x: i2b + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 arg1 B + 0 5 1 arg2 B } SourceFile: "TinyFrameworkNative_host.java" RuntimeInvisibleAnnotations: @@ -2614,6 +2706,187 @@ SourceFile: "TinyFrameworkPackageRedirect.java" RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.class + Compiled from "TinyFrameworkRenamedClassCaller.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 2, attributes: 2 + public com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=1, locals=1, args_size=1 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller; + + public static int foo(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: dup + x: iload_0 + x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed."<init>":(I)V + x: invokevirtual #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getValue:()I + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 12 0 value I +} +SourceFile: "TinyFrameworkRenamedClassCaller.java" +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.class + Compiled from "TinyFrameworkToBeRenamed.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 2 + private final int mValue; + descriptor: I + flags: (0x0012) ACC_PRIVATE, ACC_FINAL + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed(int); + descriptor: (I)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=2, locals=2, args_size=2 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: aload_0 + x: iload_1 + x: putfield #x // Field mValue:I + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + 0 10 1 value I + + public int getValue(); + descriptor: ()I + flags: (0x0001) ACC_PUBLIC + Code: + stack=1, locals=1, args_size=1 + x: aload_0 + x: getfield #x // Field mValue:I + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; +} +SourceFile: "TinyFrameworkToBeRenamed.java" +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/packagetest/A.class + Compiled from "A.java" +public class com.android.hoststubgen.test.tinyframework.packagetest.A + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/A + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 1, attributes: 1 + public com.android.hoststubgen.test.tinyframework.packagetest.A(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=1, locals=1, args_size=1 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/packagetest/A; +} +SourceFile: "A.java" +## Class: com/android/hoststubgen/test/tinyframework/packagetest/B.class + Compiled from "B.java" +public class com.android.hoststubgen.test.tinyframework.packagetest.B + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/B + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 1, attributes: 1 + public com.android.hoststubgen.test.tinyframework.packagetest.B(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=1, locals=1, args_size=1 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/packagetest/B; +} +SourceFile: "B.java" +## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/A.class + Compiled from "A.java" +public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/A + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 1, attributes: 1 + public com.android.hoststubgen.test.tinyframework.packagetest.sub.A(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=1, locals=1, args_size=1 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/packagetest/sub/A; +} +SourceFile: "A.java" +## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/B.class + Compiled from "B.java" +public class com.android.hoststubgen.test.tinyframework.packagetest.sub.B + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/B + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 1, attributes: 1 + public com.android.hoststubgen.test.tinyframework.packagetest.sub.B(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=1, locals=1, args_size=1 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/packagetest/sub/B; +} +SourceFile: "B.java" ## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C1.class Compiled from "C1.java" public class com.android.hoststubgen.test.tinyframework.subclasstest.C1 diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt index 37de857b9780..17ba48c67d98 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt @@ -122,6 +122,100 @@ RuntimeVisibleAnnotations: NestMembers: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy +## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R$Nested + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 4 + public static int[] ARRAY; + descriptor: [I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public com.android.hoststubgen.test.tinyframework.R$Nested(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + static {}; + descriptor: ()V + flags: (0x0008) ACC_STATIC + Code: + stack=3, locals=0, args_size=0 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R +SourceFile: "R.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +NestHost: class com/android/hoststubgen/test/tinyframework/R +## Class: com/android/hoststubgen/test/tinyframework/R.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 1, attributes: 4 + public com.android.hoststubgen.test.tinyframework.R(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R +SourceFile: "R.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +NestMembers: + com/android/hoststubgen/test/tinyframework/R$Nested ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class Compiled from "TinyFrameworkCallerCheck.java" class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl @@ -1554,7 +1648,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative super_class: #x // java/lang/Object - interfaces: 0, fields: 1, methods: 9, attributes: 3 + interfaces: 0, fields: 1, methods: 10, attributes: 3 int value; descriptor: I flags: (0x0000) @@ -1686,6 +1780,15 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public static native byte nativeBytePlus(byte, byte); + descriptor: (BB)B + flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkNative.java" RuntimeVisibleAnnotations: @@ -2074,6 +2177,88 @@ RuntimeVisibleAnnotations: RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.class + Compiled from "TinyFrameworkRenamedClassCaller.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 2, attributes: 3 + public com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public static int foo(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +SourceFile: "TinyFrameworkRenamedClassCaller.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/packagetest/A.class + Compiled from "A.java" +public class com.android.hoststubgen.test.tinyframework.packagetest.A + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/A + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 0, attributes: 2 +} +SourceFile: "A.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/A.class + Compiled from "A.java" +public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/A + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 0, attributes: 2 +} +SourceFile: "A.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl ## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C1.class Compiled from "C1.java" public class com.android.hoststubgen.test.tinyframework.subclasstest.C1 @@ -2284,3 +2469,62 @@ RuntimeVisibleAnnotations: RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub +## Class: rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.class + Compiled from "TinyFrameworkToBeRenamed.java" +public class rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 3 + private final int mValue; + descriptor: I + flags: (0x0012) ACC_PRIVATE, ACC_FINAL + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed(int); + descriptor: (I)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=2, args_size=2 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public int getValue(); + descriptor: ()I + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +SourceFile: "TinyFrameworkToBeRenamed.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt index c9c607c58c68..0f5f7e747a2e 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt @@ -348,6 +348,108 @@ RuntimeVisibleAnnotations: NestMembers: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy +## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R$Nested + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 4 + public static int[] ARRAY; + descriptor: [I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public com.android.hoststubgen.test.tinyframework.R$Nested(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=1, locals=1, args_size=1 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/R$Nested; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + static {}; + descriptor: ()V + flags: (0x0008) ACC_STATIC + Code: + stack=4, locals=0, args_size=0 + x: iconst_1 + x: newarray int + x: dup + x: iconst_0 + x: iconst_1 + x: iastore + x: putstatic #x // Field ARRAY:[I + x: return + LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R +SourceFile: "R.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +NestHost: class com/android/hoststubgen/test/tinyframework/R +## Class: com/android/hoststubgen/test/tinyframework/R.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 1, attributes: 4 + public com.android.hoststubgen.test.tinyframework.R(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=1, locals=1, args_size=1 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/R; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R +SourceFile: "R.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +NestMembers: + com/android/hoststubgen/test/tinyframework/R$Nested ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class Compiled from "TinyFrameworkCallerCheck.java" class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl @@ -2236,7 +2338,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative super_class: #x // java/lang/Object - interfaces: 0, fields: 1, methods: 10, attributes: 3 + interfaces: 0, fields: 1, methods: 11, attributes: 3 int value; descriptor: I flags: (0x0000) @@ -2435,6 +2537,23 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public static byte nativeBytePlus(byte, byte); + descriptor: (BB)B + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=2, locals=2, args_size=2 + x: iload_0 + x: iload_1 + x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeBytePlus:(BB)B + x: ireturn + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkNative.java" RuntimeVisibleAnnotations: @@ -2457,7 +2576,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 4, attributes: 3 + interfaces: 0, fields: 0, methods: 5, attributes: 3 public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -2551,6 +2670,31 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host RuntimeVisibleAnnotations: x: #x() com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public static byte nativeBytePlus(byte, byte); + descriptor: (BB)B + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host + x: ldc #x // String nativeBytePlus + x: ldc #x // String (BB)B + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: iload_0 + x: iload_1 + x: iadd + x: i2b + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 15 5 0 arg1 B + 15 5 1 arg2 B + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkNative_host.java" RuntimeVisibleAnnotations: @@ -3396,6 +3540,95 @@ RuntimeVisibleAnnotations: RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.class + Compiled from "TinyFrameworkRenamedClassCaller.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 2, attributes: 3 + public com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=1, locals=1, args_size=1 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public static int foo(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: dup + x: iload_0 + x: invokespecial #x // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed."<init>":(I)V + x: invokevirtual #x // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getValue:()I + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 12 0 value I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +SourceFile: "TinyFrameworkRenamedClassCaller.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/packagetest/A.class + Compiled from "A.java" +public class com.android.hoststubgen.test.tinyframework.packagetest.A + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/A + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 0, attributes: 2 +} +SourceFile: "A.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/A.class + Compiled from "A.java" +public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/A + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 0, attributes: 2 +} +SourceFile: "A.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl ## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C1.class Compiled from "C1.java" public class com.android.hoststubgen.test.tinyframework.subclasstest.C1 @@ -3786,3 +4019,70 @@ RuntimeVisibleAnnotations: RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub +## Class: rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.class + Compiled from "TinyFrameworkToBeRenamed.java" +public class rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 3 + private final int mValue; + descriptor: I + flags: (0x0012) ACC_PRIVATE, ACC_FINAL + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed(int); + descriptor: (I)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=2, locals=2, args_size=2 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: aload_0 + x: iload_1 + x: putfield #x // Field mValue:I + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + 0 10 1 value I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public int getValue(); + descriptor: ()I + flags: (0x0001) ACC_PUBLIC + Code: + stack=1, locals=1, args_size=1 + x: aload_0 + x: getfield #x // Field mValue:I + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +SourceFile: "TinyFrameworkToBeRenamed.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt index 37de857b9780..17ba48c67d98 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt @@ -122,6 +122,100 @@ RuntimeVisibleAnnotations: NestMembers: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy +## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R$Nested + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 4 + public static int[] ARRAY; + descriptor: [I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public com.android.hoststubgen.test.tinyframework.R$Nested(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + static {}; + descriptor: ()V + flags: (0x0008) ACC_STATIC + Code: + stack=3, locals=0, args_size=0 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R +SourceFile: "R.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +NestHost: class com/android/hoststubgen/test/tinyframework/R +## Class: com/android/hoststubgen/test/tinyframework/R.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 1, attributes: 4 + public com.android.hoststubgen.test.tinyframework.R(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R +SourceFile: "R.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +NestMembers: + com/android/hoststubgen/test/tinyframework/R$Nested ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class Compiled from "TinyFrameworkCallerCheck.java" class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl @@ -1554,7 +1648,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative super_class: #x // java/lang/Object - interfaces: 0, fields: 1, methods: 9, attributes: 3 + interfaces: 0, fields: 1, methods: 10, attributes: 3 int value; descriptor: I flags: (0x0000) @@ -1686,6 +1780,15 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public static native byte nativeBytePlus(byte, byte); + descriptor: (BB)B + flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkNative.java" RuntimeVisibleAnnotations: @@ -2074,6 +2177,88 @@ RuntimeVisibleAnnotations: RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.class + Compiled from "TinyFrameworkRenamedClassCaller.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 2, attributes: 3 + public com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public static int foo(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +SourceFile: "TinyFrameworkRenamedClassCaller.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/packagetest/A.class + Compiled from "A.java" +public class com.android.hoststubgen.test.tinyframework.packagetest.A + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/A + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 0, attributes: 2 +} +SourceFile: "A.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/A.class + Compiled from "A.java" +public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/A + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 0, attributes: 2 +} +SourceFile: "A.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl ## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C1.class Compiled from "C1.java" public class com.android.hoststubgen.test.tinyframework.subclasstest.C1 @@ -2284,3 +2469,62 @@ RuntimeVisibleAnnotations: RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub +## Class: rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.class + Compiled from "TinyFrameworkToBeRenamed.java" +public class rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 3 + private final int mValue; + descriptor: I + flags: (0x0012) ACC_PRIVATE, ACC_FINAL + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed(int); + descriptor: (I)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=2, args_size=2 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public int getValue(); + descriptor: ()I + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +SourceFile: "TinyFrameworkToBeRenamed.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt index a57907d9398b..3beea643823a 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt @@ -481,6 +481,136 @@ RuntimeVisibleAnnotations: NestMembers: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy +## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R$Nested + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 4 + public static int[] ARRAY; + descriptor: [I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public com.android.hoststubgen.test.tinyframework.R$Nested(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/R$Nested + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/R$Nested; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + static {}; + descriptor: ()V + flags: (0x0008) ACC_STATIC + Code: + stack=4, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/R$Nested + x: ldc #x // String <clinit> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // class com/android/hoststubgen/test/tinyframework/R$Nested + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: iconst_1 + x: newarray int + x: dup + x: iconst_0 + x: iconst_1 + x: iastore + x: putstatic #x // Field ARRAY:[I + x: return + LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R +SourceFile: "R.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +NestHost: class com/android/hoststubgen/test/tinyframework/R +## Class: com/android/hoststubgen/test/tinyframework/R.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 2, attributes: 4 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/R + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public com.android.hoststubgen.test.tinyframework.R(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/R + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/R; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R +SourceFile: "R.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +NestMembers: + com/android/hoststubgen/test/tinyframework/R$Nested ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class Compiled from "TinyFrameworkCallerCheck.java" class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl @@ -2743,7 +2873,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative super_class: #x // java/lang/Object - interfaces: 0, fields: 1, methods: 11, attributes: 3 + interfaces: 0, fields: 1, methods: 12, attributes: 3 int value; descriptor: I flags: (0x0000) @@ -3002,6 +3132,28 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public static byte nativeBytePlus(byte, byte); + descriptor: (BB)B + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative + x: ldc #x // String nativeBytePlus + x: ldc #x // String (BB)B + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: iload_0 + x: iload_1 + x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeBytePlus:(BB)B + x: ireturn + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkNative.java" RuntimeVisibleAnnotations: @@ -3024,7 +3176,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 5, attributes: 3 + interfaces: 0, fields: 0, methods: 6, attributes: 3 private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -3148,6 +3300,36 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host RuntimeVisibleAnnotations: x: #x() com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public static byte nativeBytePlus(byte, byte); + descriptor: (BB)B + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host + x: ldc #x // String nativeBytePlus + x: ldc #x // String (BB)B + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host + x: ldc #x // String nativeBytePlus + x: ldc #x // String (BB)B + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: iload_0 + x: iload_1 + x: iadd + x: i2b + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 26 5 0 arg1 B + 26 5 1 arg2 B + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkNative_host.java" RuntimeVisibleAnnotations: @@ -4226,6 +4408,133 @@ RuntimeVisibleAnnotations: RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.class + Compiled from "TinyFrameworkRenamedClassCaller.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 3, attributes: 3 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public static int foo(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller + x: ldc #x // String foo + x: ldc #x // String (I)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: new #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: dup + x: iload_0 + x: invokespecial #x // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed."<init>":(I)V + x: invokevirtual #x // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getValue:()I + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 12 0 value I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +SourceFile: "TinyFrameworkRenamedClassCaller.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/packagetest/A.class + Compiled from "A.java" +public class com.android.hoststubgen.test.tinyframework.packagetest.A + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/A + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 1, attributes: 2 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/packagetest/A + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return +} +SourceFile: "A.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/A.class + Compiled from "A.java" +public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/A + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 1, attributes: 2 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/packagetest/sub/A + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return +} +SourceFile: "A.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl ## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C1.class Compiled from "C1.java" public class com.android.hoststubgen.test.tinyframework.subclasstest.C1 @@ -4809,3 +5118,90 @@ RuntimeVisibleAnnotations: RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub +## Class: rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.class + Compiled from "TinyFrameworkToBeRenamed.java" +public class rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 3, attributes: 3 + private final int mValue; + descriptor: I + flags: (0x0012) ACC_PRIVATE, ACC_FINAL + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed(int); + descriptor: (I)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: ldc #x // String <init> + x: ldc #x // String (I)V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: aload_0 + x: iload_1 + x: putfield #x // Field mValue:I + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + 11 10 1 value I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public int getValue(); + descriptor: ()I + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: ldc #x // String getValue + x: ldc #x // String ()I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: getfield #x // Field mValue:I + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +SourceFile: "TinyFrameworkToBeRenamed.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt index d30208452a40..75c9721020bd 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt @@ -19,6 +19,9 @@ class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy ~com # Heuristics rule: Stub all the AIDL classes. class :aidl stubclass +# Heuristics rule: Stub all the R classes. +class :r stubclass + # Default is "remove", so let's put all the base classes / interfaces in the stub first. class com.android.hoststubgen.test.tinyframework.subclasstest.C1 stub class com.android.hoststubgen.test.tinyframework.subclasstest.C2 stub @@ -37,3 +40,17 @@ class *com.android.hoststubgen.test.tinyframework.subclasstest.CA remove class *com.android.hoststubgen.test.tinyframework.subclasstest.I1 keep class *com.android.hoststubgen.test.tinyframework.subclasstest.IA remove + +# Test package directive +package com.android.hoststubgen.test.tinyframework.packagetest stub +class com.android.hoststubgen.test.tinyframework.packagetest.B remove +class com.android.hoststubgen.test.tinyframework.packagetest.sub.B remove +# The following rules are the same as above +# class com.android.hoststubgen.test.tinyframework.packagetest.A stub +# class com.android.hoststubgen.test.tinyframework.packagetest.sub.A stub + + +# "rename" takes a type internal name, so '/'s is used as a separator. +# The leading / in the prefix is not needed (it'll be stripped), but it's added to make +# sure the stripping works. +rename ^.*/TinyFrameworkToBeRenamed$ /rename_prefix/
\ No newline at end of file diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py index 1dec6ab092cb..cee29dcd1d59 100755 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py @@ -46,7 +46,6 @@ def check_one_file(filename): class TestWithGoldenOutput(unittest.TestCase): # Test to check the generated jar files to the golden output. - @unittest.skip("Disabled until JDK 21 is merged and the golden files updated") def test_compare_to_golden(self): files = os.listdir(GOLDEN_DIR) files.sort() diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/R.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/R.java new file mode 100644 index 000000000000..b1bedf4b6853 --- /dev/null +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/R.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2024 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.hoststubgen.test.tinyframework; + +public class R { + public static class Nested { + public static int[] ARRAY = new int[] {1}; + } +} diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.java index ab387e0938c3..6d8a48a37fea 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.java +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.java @@ -73,7 +73,8 @@ public class TinyFrameworkClassAnnotations { @HostSideTestSubstitute(suffix = "_host") public static native int nativeAddThree(int value); - public static int nativeAddThree_host(int value) { + // This method is private, but at runtime, it'll inherit the visibility of the original method + private static int nativeAddThree_host(int value) { return value + 3; } diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java index 5a5e22db59e5..09ee183a2dcc 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java @@ -52,4 +52,6 @@ public class TinyFrameworkNative { public static void nativeStillNotSupported_should_be_like_this() { throw new RuntimeException(); } + + public static native byte nativeBytePlus(byte arg1, byte arg2); } diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java index 749ebaa378e3..b23c21602967 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java @@ -34,4 +34,8 @@ public class TinyFrameworkNative_host { public static int nativeNonStaticAddToValue(TinyFrameworkNative source, int arg) { return source.value + arg; } + + public static byte nativeBytePlus(byte arg1, byte arg2) { + return (byte) (arg1 + arg2); + } } diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.java new file mode 100644 index 000000000000..31a164af03f5 --- /dev/null +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.java @@ -0,0 +1,28 @@ +/* + * 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.hoststubgen.test.tinyframework; + +import android.hosttest.annotation.HostSideTestWholeClassStub; + +@HostSideTestWholeClassStub +public class TinyFrameworkRenamedClassCaller { + /** Calls the class that'll be renamed. */ + public static int foo(int value) { + // When TinyFrameworkToBeRenamed gets renamed, this callsite should be updated too, + // so this code should work as-is. + return new TinyFrameworkToBeRenamed(value).getValue(); + } +} diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.java new file mode 100644 index 000000000000..1430bcb0276b --- /dev/null +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.java @@ -0,0 +1,34 @@ +/* + * 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.hoststubgen.test.tinyframework; + +import android.hosttest.annotation.HostSideTestWholeClassStub; + +/** + * This class will be renamed by the "rename" directive in the policy file. + */ +@HostSideTestWholeClassStub +public class TinyFrameworkToBeRenamed { + private final int mValue; + + public TinyFrameworkToBeRenamed(int value) { + mValue = value; + } + + public int getValue() { + return mValue; + } +} diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/A.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/A.java new file mode 100644 index 000000000000..6a52e4401b45 --- /dev/null +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/A.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2024 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.hoststubgen.test.tinyframework.packagetest; + +public class A { +} diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/B.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/B.java new file mode 100644 index 000000000000..1374a288f7aa --- /dev/null +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/B.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2024 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.hoststubgen.test.tinyframework.packagetest; + +public class B { +} diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/sub/A.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/sub/A.java new file mode 100644 index 000000000000..361a7fd04842 --- /dev/null +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/sub/A.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2024 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.hoststubgen.test.tinyframework.packagetest.sub; + +public class A { +} diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/sub/B.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/sub/B.java new file mode 100644 index 000000000000..716595a44243 --- /dev/null +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/packagetest/sub/B.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2024 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.hoststubgen.test.tinyframework.packagetest.sub; + +public class B { +} diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java index ba17c75132f2..bf0f6545d1f5 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java @@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; +import com.android.hoststubgen.test.tinyframework.R.Nested; import com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.SubClass; import org.junit.Rule; @@ -154,13 +155,22 @@ public class TinyFrameworkClassTest { } @Test + public void testNativeSubstitutionLong() { + assertThat(TinyFrameworkNative.nativeLongPlus(1L, 2L)).isEqualTo(3L); + } + + @Test + public void testNativeSubstitutionByte() { + assertThat(TinyFrameworkNative.nativeBytePlus((byte) 3, (byte) 4)).isEqualTo(7); + } + + @Test public void testNativeSubstitutionClass_nonStatic() { TinyFrameworkNative instance = new TinyFrameworkNative(); instance.setValue(5); assertThat(instance.nativeNonStaticAddToValue(3)).isEqualTo(8); } - @Test public void testSubstituteNativeWithThrow() throws Exception { // We can't use TinyFrameworkNative.nativeStillNotSupported() directly in this class, @@ -319,4 +329,14 @@ public class TinyFrameworkClassTest { assertThat(IPretendingAidl.Stub.addOne(1)).isEqualTo(2); assertThat(IPretendingAidl.Stub.Proxy.addTwo(1)).isEqualTo(3); } + + @Test + public void testRFileHeuristics() { + assertThat(Nested.ARRAY.length).isEqualTo(1); + } + + @Test + public void testTypeRename() { + assertThat(TinyFrameworkRenamedClassCaller.foo(1)).isEqualTo(1); + } } diff --git a/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/utils/TrieTest.kt b/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/utils/TrieTest.kt new file mode 100644 index 000000000000..081d03909926 --- /dev/null +++ b/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/utils/TrieTest.kt @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2024 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.hoststubgen.utils + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test + +class TrieTest { + + private class TestTrie : Trie<String, Char, Int>() { + override fun splitToComponents(key: String): Iterator<Char> { + return key.toCharArray().iterator() + } + } + + @Test + fun testPrefixTree() { + val trie = TestTrie() + trie["ab"] = 1 + trie["abc"] = 2 + trie["ab123"] = 3 + assertNull(trie["a"]) + assertNull(trie["x"]) + assertNull(trie["a1"]) + assertEquals(1, trie["ab"]) + assertEquals(2, trie["abc"]) + assertEquals(2, trie["abcd"]) + assertEquals(1, trie["ab1"]) + assertEquals(1, trie["ab12"]) + assertEquals(3, trie["ab123"]) + assertEquals(1, trie["ab@"]) + } +} diff --git a/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/visitors/HelperTest.kt b/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/visitors/HelperTest.kt index 0ea90ed2fbf0..75e2536a98fa 100644 --- a/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/visitors/HelperTest.kt +++ b/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/visitors/HelperTest.kt @@ -71,7 +71,7 @@ class HelperTest { addClass(cn) } - fun check(from: MethodNode?, to: MethodNode?, expected: Boolean) { + fun check(from: MethodNode?, to: MethodNode?, expected: Int) { assertThat(checkSubstitutionMethodCompatibility( classes, cn.name, @@ -82,21 +82,21 @@ class HelperTest { )).isEqualTo(expected) } - check(staticPublic, staticPublic, true) - check(staticPrivate, staticPrivate, true) - check(nonStaticPublic, nonStaticPublic, true) - check(nonStaticPProtected, nonStaticPProtected, true) + check(staticPublic, staticPublic, Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC) + check(staticPrivate, staticPrivate, Opcodes.ACC_PRIVATE or Opcodes.ACC_STATIC) + check(nonStaticPublic, nonStaticPublic, Opcodes.ACC_PUBLIC) + check(nonStaticPProtected, nonStaticPProtected, 0) - check(staticPublic, null, false) - check(null, staticPublic, false) + check(staticPublic, null, NOT_COMPATIBLE) + check(null, staticPublic, NOT_COMPATIBLE) - check(staticPublic, nonStaticPublic, false) - check(nonStaticPublic, staticPublic, false) + check(staticPublic, nonStaticPublic, NOT_COMPATIBLE) + check(nonStaticPublic, staticPublic, NOT_COMPATIBLE) - check(staticPublic, staticPrivate, false) - check(staticPrivate, staticPublic, true) + check(staticPublic, staticPrivate, Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC) + check(staticPrivate, staticPublic, Opcodes.ACC_PRIVATE or Opcodes.ACC_STATIC) - check(nonStaticPublic, nonStaticPProtected, false) - check(nonStaticPProtected, nonStaticPublic, true) + check(nonStaticPublic, nonStaticPProtected, Opcodes.ACC_PUBLIC) + check(nonStaticPProtected, nonStaticPublic, 0) } }
\ No newline at end of file diff --git a/tools/hoststubgen/scripts/dump-jar b/tools/hoststubgen/scripts/dump-jar index 992665ed58ee..fe546fe9cc92 100755 --- a/tools/hoststubgen/scripts/dump-jar +++ b/tools/hoststubgen/scripts/dump-jar @@ -97,6 +97,7 @@ filter_output() { # - Remove the constant pool # - Remove the line number table # - Some other transient lines + # - Sometimes the javap shows mysterious warnings, so remove them too. # # `/PATTERN-1/,/PATTERN-1/{//!d}` is a trick to delete lines between two patterns, without # the start and the end lines. @@ -106,7 +107,8 @@ filter_output() { -e '/^ *line *[0-9][0-9]*: *[0-9][0-9]*$/d' \ -e '/SHA-256 checksum/d' \ -e '/Last modified/d' \ - -e '/^Classfile jar/d' + -e '/^Classfile jar/d' \ + -e '/\[warning\]/d' else cat # Print as-is. fi diff --git a/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt b/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt index 4c1fa6ec40b3..4995eebdd79e 100644 --- a/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt +++ b/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt @@ -30,7 +30,7 @@ import javax.lang.model.SourceVersion import javax.lang.model.element.AnnotationValue import javax.lang.model.element.TypeElement import javax.tools.Diagnostic.Kind -import javax.tools.StandardLocation.CLASS_OUTPUT +import javax.tools.StandardLocation.SOURCE_OUTPUT import kotlin.collections.set /** @@ -126,7 +126,7 @@ class IntDefProcessor : AbstractProcessor() { @Throws(IOException::class) private fun outputToFile(annotationTypeToIntDefMapping: Map<String, IntDefMapping>) { val resource = processingEnv.filer.createResource( - CLASS_OUTPUT, "com.android.winscope", outputName) + SOURCE_OUTPUT, "com.android.winscope", outputName) val writer = resource.openWriter() serializeTo(annotationTypeToIntDefMapping, writer) writer.close() diff --git a/tools/processors/intdef_mappings/test/android/processor/IntDefProcessorTest.kt b/tools/processors/intdef_mappings/test/android/processor/IntDefProcessorTest.kt index c0c159c98aac..d87b6df901b2 100644 --- a/tools/processors/intdef_mappings/test/android/processor/IntDefProcessorTest.kt +++ b/tools/processors/intdef_mappings/test/android/processor/IntDefProcessorTest.kt @@ -24,7 +24,7 @@ import junit.framework.Assert.assertEquals import org.junit.Test import java.io.StringWriter import javax.tools.JavaFileObject -import javax.tools.StandardLocation.CLASS_OUTPUT +import javax.tools.StandardLocation.SOURCE_OUTPUT /** * Tests for [IntDefProcessor] @@ -112,7 +112,7 @@ class IntDefProcessorTest { .compile(filesToCompile.toMutableList()) assertThat(compilation).succeeded() - assertThat(compilation).generatedFile(CLASS_OUTPUT, "com.android.winscope", + assertThat(compilation).generatedFile(SOURCE_OUTPUT, "com.android.winscope", "intDefMapping.json").contentsAsUtf8String().isEqualTo(expectedFile) } diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt index 59db66b95250..fd7d2b35bb6f 100644 --- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt @@ -27,9 +27,16 @@ import com.github.javaparser.ast.CompilationUnit import com.github.javaparser.ast.Modifier import com.github.javaparser.ast.NodeList import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration +import com.github.javaparser.ast.expr.ArrayAccessExpr +import com.github.javaparser.ast.expr.ArrayCreationExpr +import com.github.javaparser.ast.expr.ArrayInitializerExpr import com.github.javaparser.ast.expr.AssignExpr +import com.github.javaparser.ast.expr.BooleanLiteralExpr +import com.github.javaparser.ast.expr.Expression import com.github.javaparser.ast.expr.FieldAccessExpr +import com.github.javaparser.ast.expr.IntegerLiteralExpr import com.github.javaparser.ast.expr.MethodCallExpr +import com.github.javaparser.ast.expr.MethodReferenceExpr import com.github.javaparser.ast.expr.NameExpr import com.github.javaparser.ast.expr.NullLiteralExpr import com.github.javaparser.ast.expr.ObjectCreationExpr @@ -49,8 +56,7 @@ import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import java.util.jar.JarOutputStream import java.util.zip.ZipEntry -import kotlin.math.abs -import kotlin.random.Random +import kotlin.math.absoluteValue import kotlin.system.exitProcess object ProtoLogTool { @@ -82,7 +88,11 @@ object ProtoLogTool { } private fun processClasses(command: CommandOptions) { - val generationHash = abs(Random.nextInt()) + // A deterministic hash based on the group jar path and the source files we are processing. + // The hash is required to make sure different ProtoLogImpls don't conflict. + val generationHash = (command.javaSourceArgs.toTypedArray() + command.protoLogGroupsJarArg) + .contentHashCode().absoluteValue + // Need to generate a new impl class to inject static constants into the class. val generatedProtoLogImplClass = "com.android.internal.protolog.ProtoLogImpl_$generationHash" @@ -169,6 +179,8 @@ object ProtoLogTool { val classNameNode = classDeclaration.findFirst(SimpleName::class.java).get() classNameNode.setId(protoLogImplGenName) + injectCacheClass(classDeclaration, groups, protoLogGroupsClassName) + injectConstants(classDeclaration, viewerConfigFilePath, legacyViewerConfigFilePath, legacyOutputFilePath, groups, protoLogGroupsClassName) @@ -217,6 +229,12 @@ object ProtoLogTool { field.variables.first().setInitializer( MethodCallExpr().setName("createLogGroupsMap")) } + ProtoLogToolInjected.Value.CACHE_UPDATER.name -> { + field.setFinal(true) + field.variables.first().setInitializer(MethodReferenceExpr() + .setScope(NameExpr("Cache")) + .setIdentifier("update")) + } else -> error("Unhandled ProtoLogToolInjected value: $valueName.") } } @@ -263,6 +281,61 @@ object ProtoLogTool { } } + private fun injectCacheClass( + classDeclaration: ClassOrInterfaceDeclaration, + groups: Map<String, LogGroup>, + protoLogGroupsClassName: String, + ) { + val cacheClass = ClassOrInterfaceDeclaration() + .setName("Cache") + .setPublic(true) + .setStatic(true) + for (group in groups) { + val nodeList = NodeList<Expression>() + val defaultVal = BooleanLiteralExpr(group.value.textEnabled || group.value.enabled) + repeat(LogLevel.entries.size) { nodeList.add(defaultVal) } + cacheClass.addFieldWithInitializer( + "boolean[]", + "${group.key}_enabled", + ArrayCreationExpr().setElementType("boolean[]").setInitializer( + ArrayInitializerExpr().setValues(nodeList) + ), + Modifier.Keyword.PUBLIC, + Modifier.Keyword.STATIC + ) + } + + val updateBlockStmt = BlockStmt() + for (group in groups) { + for (level in LogLevel.entries) { + updateBlockStmt.addStatement( + AssignExpr() + .setTarget( + ArrayAccessExpr() + .setName(NameExpr("${group.key}_enabled")) + .setIndex(IntegerLiteralExpr(level.ordinal)) + ).setValue( + MethodCallExpr() + .setName("isEnabled") + .setArguments(NodeList( + FieldAccessExpr() + .setScope(NameExpr(protoLogGroupsClassName)) + .setName(group.value.name), + FieldAccessExpr() + .setScope(NameExpr("LogLevel")) + .setName(level.toString()), + )) + ) + ) + } + } + + cacheClass.addMethod("update").setPrivate(true).setStatic(true) + .setBody(updateBlockStmt) + + classDeclaration.addMember(cacheClass) + } + private fun tryParse(code: String, fileName: String): CompilationUnit { try { return StaticJavaParser.parse(code) diff --git a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt index 2b7164191dd0..6a8a0717b2f1 100644 --- a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt +++ b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt @@ -22,6 +22,7 @@ import com.github.javaparser.StaticJavaParser import com.github.javaparser.ast.CompilationUnit import com.github.javaparser.ast.NodeList import com.github.javaparser.ast.body.VariableDeclarator +import com.github.javaparser.ast.expr.ArrayAccessExpr import com.github.javaparser.ast.expr.CastExpr import com.github.javaparser.ast.expr.Expression import com.github.javaparser.ast.expr.FieldAccessExpr @@ -35,6 +36,8 @@ import com.github.javaparser.ast.expr.TypeExpr import com.github.javaparser.ast.expr.VariableDeclarationExpr import com.github.javaparser.ast.stmt.BlockStmt import com.github.javaparser.ast.stmt.ExpressionStmt +import com.github.javaparser.ast.stmt.IfStmt +import com.github.javaparser.ast.stmt.Statement import com.github.javaparser.ast.type.ArrayType import com.github.javaparser.ast.type.ClassOrInterfaceType import com.github.javaparser.ast.type.PrimitiveType @@ -74,6 +77,8 @@ class SourceTransformer( private val protoLogImplClassNode = StaticJavaParser.parseExpression<FieldAccessExpr>(protoLogImplClassName) + private val protoLogImplCacheClassNode = + StaticJavaParser.parseExpression<FieldAccessExpr>("$protoLogImplClassName.Cache") private var processedCode: MutableList<String> = mutableListOf() private var offsets: IntArray = IntArray(0) /** The path of the file being processed, relative to $ANDROID_BUILD_TOP */ @@ -121,8 +126,9 @@ class SourceTransformer( group: LogGroup, level: LogLevel, messageString: String - ): BlockStmt { + ): Statement { val hash = CodeUtils.hash(packagePath, messageString, level, group) + val newCall = call.clone() if (!group.textEnabled) { // Remove message string if text logging is not enabled by default. @@ -166,11 +172,15 @@ class SourceTransformer( } blockStmt.addStatement(ExpressionStmt(newCall)) - return blockStmt + val isLogEnabled = ArrayAccessExpr() + .setName(NameExpr("$protoLogImplCacheClassNode.${group.name}_enabled")) + .setIndex(IntegerLiteralExpr(level.ordinal)) + + return IfStmt(isLogEnabled, blockStmt, null) } private fun injectProcessedCallStatementInCode( - processedCallStatement: BlockStmt, + processedCallStatement: Statement, parentStmt: ExpressionStmt ) { // Inline the new statement. diff --git a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt index de0b5bae118e..82aa93da613b 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt @@ -76,7 +76,7 @@ class SourceTransformerTest { class Test { void test() { - { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); } + if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); } } } """.trimIndent() @@ -86,7 +86,7 @@ class SourceTransformerTest { class Test { void test() { - { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, -4447034859795564700L, 9, "test %d %f " + "abc %s\n test", protoLogParam0, protoLogParam1, protoLogParam2); + if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, -4447034859795564700L, 9, "test %d %f " + "abc %s\n test", protoLogParam0, protoLogParam1, protoLogParam2); } } @@ -98,8 +98,8 @@ class SourceTransformerTest { class Test { void test() { - { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); } /* ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); */ { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); } - { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); } + if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); } /* ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); */ if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); } + if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); } } } """.trimIndent() @@ -109,7 +109,7 @@ class SourceTransformerTest { class Test { void test() { - { org.example.ProtoLogImpl.w(TEST_GROUP, 3218600869538902408L, 0, "test", (Object[]) null); } + if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { org.example.ProtoLogImpl.w(TEST_GROUP, 3218600869538902408L, 0, "test", (Object[]) null); } } } """.trimIndent() @@ -119,7 +119,7 @@ class SourceTransformerTest { class Test { void test() { - { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, null, protoLogParam0, protoLogParam1); } + if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, null, protoLogParam0, protoLogParam1); } } } """.trimIndent() @@ -129,7 +129,7 @@ class SourceTransformerTest { class Test { void test() { - { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, -4447034859795564700L, 9, null, protoLogParam0, protoLogParam1, protoLogParam2); + if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, -4447034859795564700L, 9, null, protoLogParam0, protoLogParam1, protoLogParam2); } } diff --git a/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt b/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt index 0b619488c49c..9c443324defb 100644 --- a/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt +++ b/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt @@ -23,13 +23,21 @@ import java.io.IOException import java.util.zip.ZipFile fun main(args: Array<String>) { - if (args.size != 2) { + if (args.size < 2 || args.size > 3) { usage() } val zipFileName = args[0] val aidlFileName = args[1] + var stable = false + if (args.size == 3) { + if (args[2] != "--guarantee_stable") { + usage() + } + stable = true + } + val zipFile: ZipFile try { @@ -55,6 +63,9 @@ fun main(args: Array<String>) { val outFile = File(aidlFileName) val outWriter = outFile.bufferedWriter() for (parcelable in parcelables) { + if (stable) { + outWriter.write("@JavaOnlyStableParcelable ") + } outWriter.write("parcelable ") outWriter.write(parcelable.replace('/', '.').replace('$', '.')) outWriter.write(";\n") diff --git a/tools/systemfeatures/Android.bp b/tools/systemfeatures/Android.bp index 2cebfe9790d0..aca25eb8f603 100644 --- a/tools/systemfeatures/Android.bp +++ b/tools/systemfeatures/Android.bp @@ -30,9 +30,9 @@ java_binary_host { genrule { name: "systemfeatures-gen-tests-srcs", cmd: "$(location systemfeatures-gen-tool) com.android.systemfeatures.RwNoFeatures --readonly=false > $(location RwNoFeatures.java) && " + - "$(location systemfeatures-gen-tool) com.android.systemfeatures.RoNoFeatures --readonly=true > $(location RoNoFeatures.java) && " + + "$(location systemfeatures-gen-tool) com.android.systemfeatures.RoNoFeatures --readonly=true --feature-apis=WATCH > $(location RoNoFeatures.java) && " + "$(location systemfeatures-gen-tool) com.android.systemfeatures.RwFeatures --readonly=false --feature=WATCH:1 --feature=WIFI:0 --feature=VULKAN:-1 --feature=AUTO: > $(location RwFeatures.java) && " + - "$(location systemfeatures-gen-tool) com.android.systemfeatures.RoFeatures --readonly=true --feature=WATCH:1 --feature=WIFI:0 --feature=VULKAN:-1 --feature=AUTO: > $(location RoFeatures.java)", + "$(location systemfeatures-gen-tool) com.android.systemfeatures.RoFeatures --readonly=true --feature=WATCH:1 --feature=WIFI:0 --feature=VULKAN:-1 --feature=AUTO: --feature-apis=WATCH,PC > $(location RoFeatures.java)", out: [ "RwNoFeatures.java", "RoNoFeatures.java", diff --git a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt index 9bfda451067f..e537ffcb56bd 100644 --- a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt +++ b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt @@ -32,6 +32,7 @@ import javax.lang.model.element.Modifier * <pre> * <cmd> com.foo.RoSystemFeatures --readonly=true \ * --feature=WATCH:0 --feature=AUTOMOTIVE: --feature=VULKAN:9348 + * --feature-apis=WATCH,PC,LEANBACK * </pre> * * This generates a class that has the following signature: @@ -45,12 +46,15 @@ import javax.lang.model.element.Modifier * public static boolean hasFeatureAutomotive(Context context); * @AssumeTrueForR8 * public static boolean hasFeatureVulkan(Context context); + * public static boolean hasFeaturePc(Context context); + * public static boolean hasFeatureLeanback(Context context); * public static Boolean maybeHasFeature(String feature, int version); * } * </pre> */ object SystemFeaturesGenerator { private const val FEATURE_ARG = "--feature=" + private const val FEATURE_APIS_ARG = "--feature-apis=" private const val READONLY_ARG = "--readonly=" private val PACKAGEMANAGER_CLASS = ClassName.get("android.content.pm", "PackageManager") private val CONTEXT_CLASS = ClassName.get("android.content", "Context") @@ -64,6 +68,15 @@ object SystemFeaturesGenerator { println(" Options:") println(" --readonly=true|false Whether to encode features as build-time constants") println(" --feature=\$NAME:\$VER A feature+version pair (blank version == disabled)") + println(" This will always generate associated query APIs,") + println(" adding to or replacing those from `--feature-apis=`.") + println(" --feature-apis=\$NAME_1,\$NAME_2") + println(" A comma-separated set of features for which to always") + println(" generate named query APIs. If a feature in this set is") + println(" not explicitly defined via `--feature=`, then a simple") + println(" runtime passthrough API will be generated, regardless") + println(" of the `--readonly` flag. This allows decoupling the") + println(" API surface from variations in device feature sets.") } /** Main entrypoint for build-time system feature codegen. */ @@ -76,18 +89,42 @@ object SystemFeaturesGenerator { var readonly = false var outputClassName: ClassName? = null - val features = mutableListOf<FeatureInfo>() + val featureArgs = mutableListOf<FeatureArg>() + // We could just as easily hardcode this list, as the static API surface should change + // somewhat infrequently, but this decouples the codegen from the framework completely. + val featureApiArgs = mutableSetOf<String>() for (arg in args) { when { arg.startsWith(READONLY_ARG) -> readonly = arg.substring(READONLY_ARG.length).toBoolean() arg.startsWith(FEATURE_ARG) -> { - features.add(parseFeatureArg(arg)) + featureArgs.add(parseFeatureArg(arg)) + } + arg.startsWith(FEATURE_APIS_ARG) -> { + featureApiArgs.addAll( + arg.substring(FEATURE_APIS_ARG.length).split(",").map { + parseFeatureName(it) + } + ) } else -> outputClassName = ClassName.bestGuess(arg) } } + // First load in all of the feature APIs we want to generate. Explicit feature definitions + // will then override this set with the appropriate readonly and version value. + val features = mutableMapOf<String, FeatureInfo>() + featureApiArgs.associateByTo( + features, + { it }, + { FeatureInfo(it, version = null, readonly = false) }, + ) + featureArgs.associateByTo( + features, + { it.name }, + { FeatureInfo(it.name, it.version, readonly) }, + ) + outputClassName ?: run { println("Output class name must be provided.") @@ -100,8 +137,8 @@ object SystemFeaturesGenerator { .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addJavadoc("@hide") - addFeatureMethodsToClass(classBuilder, readonly, features) - addMaybeFeatureMethodToClass(classBuilder, readonly, features) + addFeatureMethodsToClass(classBuilder, features.values) + addMaybeFeatureMethodToClass(classBuilder, features.values) // TODO(b/203143243): Add validation of build vs runtime values to ensure consistency. JavaFile.builder(outputClassName.packageName(), classBuilder.build()) @@ -115,13 +152,16 @@ object SystemFeaturesGenerator { * * "--feature=WATCH:7" -> Feature enabled w/ version 7 * * "--feature=WATCH:" -> Feature disabled */ - private fun parseFeatureArg(arg: String): FeatureInfo { + private fun parseFeatureArg(arg: String): FeatureArg { val featureArgs = arg.substring(FEATURE_ARG.length).split(":") - val name = featureArgs[0].let { if (!it.startsWith("FEATURE_")) "FEATURE_$it" else it } + val name = parseFeatureName(featureArgs[0]) val version = featureArgs.getOrNull(1)?.toIntOrNull() - return FeatureInfo(name, version) + return FeatureArg(name, version) } + private fun parseFeatureName(name: String): String = + if (name.startsWith("FEATURE_")) name else "FEATURE_$name" + /* * Adds per-feature query methods to the class with the form: * {@code public static boolean hasFeatureX(Context context)}, @@ -129,8 +169,7 @@ object SystemFeaturesGenerator { */ private fun addFeatureMethodsToClass( builder: TypeSpec.Builder, - readonly: Boolean, - features: List<FeatureInfo> + features: Collection<FeatureInfo>, ) { for (feature in features) { // Turn "FEATURE_FOO" into "hasFeatureFoo". @@ -142,7 +181,7 @@ object SystemFeaturesGenerator { .returns(Boolean::class.java) .addParameter(CONTEXT_CLASS, "context") - if (readonly) { + if (feature.readonly) { val featureEnabled = compareValues(feature.version, 0) >= 0 methodBuilder.addAnnotation( if (featureEnabled) ASSUME_TRUE_CLASS else ASSUME_FALSE_CLASS @@ -158,19 +197,17 @@ object SystemFeaturesGenerator { builder.addMethod(methodBuilder.build()) } - if (!readonly) { - builder.addMethod( - MethodSpec.methodBuilder("hasFeatureFallback") - .addModifiers(Modifier.PRIVATE, Modifier.STATIC) - .returns(Boolean::class.java) - .addParameter(CONTEXT_CLASS, "context") - .addParameter(String::class.java, "featureName") - .addStatement( - "return context.getPackageManager().hasSystemFeature(featureName, 0)" - ) - .build() - ) - } + // This is a trivial method, even if unused based on readonly-codegen, it does little harm + // to always include it. + builder.addMethod( + MethodSpec.methodBuilder("hasFeatureFallback") + .addModifiers(Modifier.PRIVATE, Modifier.STATIC) + .returns(Boolean::class.java) + .addParameter(CONTEXT_CLASS, "context") + .addParameter(String::class.java, "featureName") + .addStatement("return context.getPackageManager().hasSystemFeature(featureName, 0)") + .build() + ) } /* @@ -185,8 +222,7 @@ object SystemFeaturesGenerator { */ private fun addMaybeFeatureMethodToClass( builder: TypeSpec.Builder, - readonly: Boolean, - features: List<FeatureInfo> + features: Collection<FeatureInfo>, ) { val methodBuilder = MethodSpec.methodBuilder("maybeHasFeature") @@ -196,16 +232,27 @@ object SystemFeaturesGenerator { .addParameter(String::class.java, "featureName") .addParameter(Int::class.java, "version") - if (readonly) { - methodBuilder.beginControlFlow("switch (featureName)") - for (feature in features) { - methodBuilder.addCode("case \$T.\$N: ", PACKAGEMANAGER_CLASS, feature.name) - if (feature.version != null) { - methodBuilder.addStatement("return \$L >= version", feature.version) - } else { - methodBuilder.addStatement("return false") - } + var hasSwitchBlock = false + for (feature in features) { + // We only return non-null results for queries against readonly-defined features. + if (!feature.readonly) { + continue + } + if (!hasSwitchBlock) { + // As an optimization, only create the switch block if needed. Even an empty + // switch-on-string block can induce a hash, which we can avoid if readonly + // support is completely disabled. + hasSwitchBlock = true + methodBuilder.beginControlFlow("switch (featureName)") } + methodBuilder.addCode("case \$T.\$N: ", PACKAGEMANAGER_CLASS, feature.name) + if (feature.version != null) { + methodBuilder.addStatement("return \$L >= version", feature.version) + } else { + methodBuilder.addStatement("return false") + } + } + if (hasSwitchBlock) { methodBuilder.addCode("default: ") methodBuilder.addStatement("break") methodBuilder.endControlFlow() @@ -214,5 +261,7 @@ object SystemFeaturesGenerator { builder.addMethod(methodBuilder.build()) } - private data class FeatureInfo(val name: String, val version: Int?) + private data class FeatureArg(val name: String, val version: Int?) + + private data class FeatureInfo(val name: String, val version: Int?, val readonly: Boolean) } diff --git a/tools/systemfeatures/tests/PackageManager.java b/tools/systemfeatures/tests/PackageManager.java index 645d500bc762..db670482065a 100644 --- a/tools/systemfeatures/tests/PackageManager.java +++ b/tools/systemfeatures/tests/PackageManager.java @@ -19,6 +19,7 @@ package android.content.pm; /** Stub for testing */ public class PackageManager { public static final String FEATURE_AUTO = "automotive"; + public static final String FEATURE_PC = "pc"; public static final String FEATURE_VULKAN = "vulkan"; public static final String FEATURE_WATCH = "watch"; public static final String FEATURE_WIFI = "wifi"; diff --git a/tools/systemfeatures/tests/SystemFeaturesGeneratorTest.java b/tools/systemfeatures/tests/SystemFeaturesGeneratorTest.java index 547d2cbd26f9..6dfd244a807b 100644 --- a/tools/systemfeatures/tests/SystemFeaturesGeneratorTest.java +++ b/tools/systemfeatures/tests/SystemFeaturesGeneratorTest.java @@ -68,6 +68,13 @@ public class SystemFeaturesGeneratorTest { assertThat(RoNoFeatures.maybeHasFeature(PackageManager.FEATURE_VULKAN, 0)).isNull(); assertThat(RoNoFeatures.maybeHasFeature(PackageManager.FEATURE_AUTO, 0)).isNull(); assertThat(RoNoFeatures.maybeHasFeature("com.arbitrary.feature", 0)).isNull(); + + // Also ensure we fall back to the PackageManager for feature APIs without an accompanying + // versioned feature definition. + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH, 0)).thenReturn(true); + assertThat(RwFeatures.hasFeatureWatch(mContext)).isTrue(); + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH, 0)).thenReturn(false); + assertThat(RwFeatures.hasFeatureWatch(mContext)).isFalse(); } @Test @@ -127,6 +134,16 @@ public class SystemFeaturesGeneratorTest { assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_AUTO, 0)).isFalse(); assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_AUTO, 100)).isFalse(); + // For feature APIs without an associated feature definition, conditional queries should + // report null, and explicit queries should report runtime-defined versions. + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_PC, 0)).thenReturn(true); + assertThat(RoFeatures.hasFeaturePc(mContext)).isTrue(); + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_PC, 0)).thenReturn(false); + assertThat(RoFeatures.hasFeaturePc(mContext)).isFalse(); + assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_PC, -1)).isNull(); + assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_PC, 0)).isNull(); + assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_PC, 100)).isNull(); + // For undefined types, conditional queries should report null (unknown). assertThat(RoFeatures.maybeHasFeature("com.arbitrary.feature", -1)).isNull(); assertThat(RoFeatures.maybeHasFeature("com.arbitrary.feature", 0)).isNull(); |