summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/app_metadata_bundles/src/aslgen/java/com/android/aslgen/Main.java28
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabel.java122
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabelFactory.java24
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/AppInfo.java143
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/AppInfoFactory.java84
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java116
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategory.java2
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategoryFactory.java3
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabels.java2
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabelsFactory.java5
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataType.java45
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataTypeFactory.java9
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/DeveloperInfo.java140
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/DeveloperInfoFactory.java59
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabels.java8
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabelsFactory.java13
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/SystemAppSafetyLabel.java47
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/SystemAppSafetyLabelFactory.java41
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/TransparencyInfo.java58
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/TransparencyInfoFactory.java51
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/XmlUtils.java158
-rw-r--r--tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/AslgenUtil.java26
-rw-r--r--tools/app_metadata_bundles/src/test/java/com/android/aslgen/AslgenTests.java6
23 files changed, 1021 insertions, 169 deletions
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
index fb7a6ab42d95..d7edfd44019c 100644
--- 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
@@ -16,8 +16,8 @@
package com.android.aslgen;
-import com.android.asllib.AndroidSafetyLabel;
-import com.android.asllib.AndroidSafetyLabel.Format;
+import com.android.asllib.AslConverter;
+import com.android.asllib.AslConverter.Format;
import com.android.asllib.util.MalformedXmlException;
import org.xml.sax.SAXException;
@@ -41,9 +41,8 @@ public class Main {
String inFile = null;
String outFile = null;
- Format inFormat = Format.NULL;
- Format outFormat = Format.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
@@ -79,11 +78,11 @@ public class Main {
throw new IllegalArgumentException("output file is required");
}
- if (inFormat == Format.NULL) {
+ if (inFormat == AslConverter.Format.NULL) {
throw new IllegalArgumentException("input format is required");
}
- if (outFormat == Format.NULL) {
+ if (outFormat == AslConverter.Format.NULL) {
throw new IllegalArgumentException("output format is required");
}
@@ -92,24 +91,23 @@ public class Main {
System.out.println("in format: " + inFormat);
System.out.println("out format: " + outFormat);
- var asl = AndroidSafetyLabel.readFromStream(new FileInputStream(inFile), inFormat);
- asl.writeToStream(new FileOutputStream(outFile), 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 Format.HUMAN_READABLE;
+ return AslConverter.Format.HUMAN_READABLE;
} else if ("od".equals(argValue)) {
- return Format.ON_DEVICE;
+ return AslConverter.Format.ON_DEVICE;
} else {
- return Format.NULL;
+ return AslConverter.Format.NULL;
}
}
private static void showUsage() {
- AndroidSafetyLabel.test();
System.err.println(
- "Usage:\n"
- );
+ "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/AndroidSafetyLabel.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabel.java
index ed9f1ac70a2b..cdb559b52c0e 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabel.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabel.java
@@ -16,125 +16,47 @@
package com.android.asllib;
-import com.android.asllib.util.MalformedXmlException;
-
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 java.util.List;
-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 AndroidSafetyLabel implements AslMarshallable {
- public enum Format {
- NULL, HUMAN_READABLE, ON_DEVICE;
- }
-
+ private final Long mVersion;
+ private final SystemAppSafetyLabel mSystemAppSafetyLabel;
private final SafetyLabels mSafetyLabels;
+ private final TransparencyInfo mTransparencyInfo;
public SafetyLabels getSafetyLabels() {
return mSafetyLabels;
}
- public AndroidSafetyLabel(SafetyLabels safetyLabels) {
+ public AndroidSafetyLabel(
+ Long version,
+ SystemAppSafetyLabel systemAppSafetyLabel,
+ SafetyLabels safetyLabels,
+ TransparencyInfo transparencyInfo) {
+ this.mVersion = version;
+ this.mSystemAppSafetyLabel = systemAppSafetyLabel;
this.mSafetyLabels = safetyLabels;
- }
-
- /** 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.getSingleElement(document, XmlUtils.HR_TAG_APP_METADATA_BUNDLES);
-
- return new AndroidSafetyLabelFactory()
- .createFromHrElements(
- List.of(
- XmlUtils.getSingleElement(
- document, XmlUtils.HR_TAG_APP_METADATA_BUNDLES)));
- case ON_DEVICE:
- throw new IllegalArgumentException(
- "Parsing from on-device format is not supported at this time.");
- 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 void writeToStream(OutputStream out, Format format)
- throws IOException, ParserConfigurationException, TransformerException {
- var docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
- var document = docBuilder.newDocument();
-
- switch (format) {
- case HUMAN_READABLE:
- throw new IllegalArgumentException(
- "Outputting human-readable format is not supported at this time.");
- case ON_DEVICE:
- for (var child : this.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 String getXmlAsString(Format format)
- throws IOException, ParserConfigurationException, TransformerException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- this.writeToStream(out, format);
- return out.toString(StandardCharsets.UTF_8);
+ 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);
- XmlUtils.appendChildren(aslEle, mSafetyLabels.toOdDomElements(doc));
- return List.of(aslEle);
- }
-
- public static void test() {
- // TODO(b/329902686): Add tests.
+ 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);
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabelFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabelFactory.java
index 7e7fcf9c08ba..3dc725b5452b 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabelFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabelFactory.java
@@ -29,11 +29,29 @@ public class AndroidSafetyLabelFactory implements AslMarshallableFactory<Android
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);
+ appMetadataBundlesEle, XmlUtils.HR_TAG_SAFETY_LABELS, false);
SafetyLabels safetyLabels =
- new SafetyLabelsFactory().createFromHrElements(List.of(safetyLabelsEle));
- return new AndroidSafetyLabel(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);
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AppInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AppInfo.java
new file mode 100644
index 000000000000..f94b6591cd10
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AppInfo.java
@@ -0,0 +1,143 @@
+/*
+ * 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 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);
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AppInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AppInfoFactory.java
new file mode 100644
index 000000000000..26d94c16c7f0
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AppInfoFactory.java
@@ -0,0 +1,84 @@
+/*
+ * 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.util.AslgenUtil;
+import com.android.asllib.util.MalformedXmlException;
+
+import org.w3c.dom.Element;
+
+import java.util.Arrays;
+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);
+ String description = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_DESCRIPTION);
+ Boolean containsAds = XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_CONTAINS_ADS);
+ Boolean obeyAps = XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_OBEY_APS);
+ Boolean adsFingerprinting =
+ XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_ADS_FINGERPRINTING);
+ Boolean securityFingerprinting =
+ XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_SECURITY_FINGERPRINTING);
+ String privacyPolicy = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_PRIVACY_POLICY);
+ List<String> securityEndpoints =
+ Arrays.stream(
+ appInfoEle
+ .getAttribute(XmlUtils.HR_ATTR_SECURITY_ENDPOINTS)
+ .split("\\|"))
+ .toList();
+ List<String> firstPartyEndpoints =
+ Arrays.stream(
+ appInfoEle
+ .getAttribute(XmlUtils.HR_ATTR_FIRST_PARTY_ENDPOINTS)
+ .split("\\|"))
+ .toList();
+ List<String> serviceProviderEndpoints =
+ Arrays.stream(
+ appInfoEle
+ .getAttribute(XmlUtils.HR_ATTR_SERVICE_PROVIDER_ENDPOINTS)
+ .split("\\|"))
+ .toList();
+ String category = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_CATEGORY);
+ String email = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_EMAIL);
+ 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);
+ }
+}
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..9dd55314e844
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java
@@ -0,0 +1,116 @@
+/*
+ * 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.util.MalformedXmlException;
+
+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.getSingleElement(document, XmlUtils.HR_TAG_APP_METADATA_BUNDLES);
+
+ return new AndroidSafetyLabelFactory()
+ .createFromHrElements(XmlUtils.listOf(appMetadataBundles));
+ case ON_DEVICE:
+ throw new IllegalArgumentException(
+ "Parsing from on-device format is not supported at this time.");
+ 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:
+ throw new IllegalArgumentException(
+ "Outputting human-readable format is not supported at this time.");
+ 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/DataCategory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategory.java
index e5ed63b74ebf..b9e06fbdfc7e 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategory.java
@@ -53,6 +53,6 @@ public class DataCategory implements AslMarshallable {
for (DataType dataType : mDataTypes.values()) {
XmlUtils.appendChildren(dataCategoryEle, dataType.toOdDomElements(doc));
}
- return List.of(dataCategoryEle);
+ return XmlUtils.listOf(dataCategoryEle);
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategoryFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategoryFactory.java
index d9463452d7bc..ae7b603c87f6 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategoryFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategoryFactory.java
@@ -36,7 +36,8 @@ public class DataCategoryFactory implements AslMarshallableFactory<DataCategory>
throw new MalformedXmlException(
String.format("Unrecognized data type name: %s", dataTypeName));
}
- dataTypeMap.put(dataTypeName, new DataTypeFactory().createFromHrElements(List.of(ele)));
+ dataTypeMap.put(
+ dataTypeName, new DataTypeFactory().createFromHrElements(XmlUtils.listOf(ele)));
}
return new DataCategory(categoryName, dataTypeMap);
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabels.java
index d2fffc0a36f6..96ec93c28c87 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabels.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabels.java
@@ -74,7 +74,7 @@ public class DataLabels implements AslMarshallable {
maybeAppendDataUsages(doc, dataLabelsEle, mDataCollected, XmlUtils.OD_NAME_DATA_COLLECTED);
maybeAppendDataUsages(doc, dataLabelsEle, mDataShared, XmlUtils.OD_NAME_DATA_SHARED);
- return List.of(dataLabelsEle);
+ return XmlUtils.listOf(dataLabelsEle);
}
private void maybeAppendDataUsages(
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabelsFactory.java
index 1adb140f446d..0e14ebf4eab9 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabelsFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabelsFactory.java
@@ -16,6 +16,7 @@
package com.android.asllib;
+import com.android.asllib.util.AslgenUtil;
import com.android.asllib.util.MalformedXmlException;
import org.w3c.dom.Element;
@@ -33,6 +34,10 @@ public class DataLabelsFactory implements AslMarshallableFactory<DataLabels> {
@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> dataAccessed =
getDataCategoriesWithTag(ele, XmlUtils.HR_TAG_DATA_ACCESSED);
Map<String, DataCategory> dataCollected =
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataType.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataType.java
index 5ba29757e19e..cecee39cbb12 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataType.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataType.java
@@ -29,15 +29,13 @@ import java.util.Set;
public class DataType implements AslMarshallable {
public enum Purpose {
- PURPOSE_APP_FUNCTIONALITY(1),
- PURPOSE_ANALYTICS(2),
- PURPOSE_DEVELOPER_COMMUNICATIONS(3),
- PURPOSE_FRAUD_PREVENTION_SECURITY(4),
- PURPOSE_ADVERTISING(5),
- PURPOSE_PERSONALIZATION(6),
- PURPOSE_ACCOUNT_MANAGEMENT(7);
-
- private static final String PURPOSE_PREFIX = "PURPOSE_";
+ APP_FUNCTIONALITY(1),
+ ANALYTICS(2),
+ DEVELOPER_COMMUNICATIONS(3),
+ FRAUD_PREVENTION_SECURITY(4),
+ ADVERTISING(5),
+ PERSONALIZATION(6),
+ ACCOUNT_MANAGEMENT(7);
private final int mValue;
@@ -57,7 +55,7 @@ public class DataType implements AslMarshallable {
return e;
}
}
- throw new IllegalArgumentException("No enum for value: " + value);
+ throw new IllegalArgumentException("No Purpose enum for value: " + value);
}
/** Get the Purpose associated with the human-readable String. */
@@ -67,15 +65,12 @@ public class DataType implements AslMarshallable {
return e;
}
}
- throw new IllegalArgumentException("No enum for str: " + s);
+ throw new IllegalArgumentException("No Purpose enum for str: " + s);
}
/** Human-readable String representation of Purpose. */
public String toString() {
- if (!this.name().startsWith(PURPOSE_PREFIX)) {
- return this.name();
- }
- return this.name().substring(PURPOSE_PREFIX.length()).toLowerCase();
+ return this.name().toLowerCase();
}
}
@@ -139,16 +134,14 @@ public class DataType implements AslMarshallable {
public List<Element> toOdDomElements(Document doc) {
Element dataTypeEle = XmlUtils.createPbundleEleWithName(doc, this.getDataTypeName());
if (!this.getPurposeSet().isEmpty()) {
- Element purposesEle = doc.createElement(XmlUtils.OD_TAG_INT_ARRAY);
- purposesEle.setAttribute(XmlUtils.OD_ATTR_NAME, XmlUtils.OD_NAME_PURPOSES);
- purposesEle.setAttribute(
- XmlUtils.OD_ATTR_NUM, String.valueOf(this.getPurposeSet().size()));
- for (DataType.Purpose purpose : this.getPurposeSet()) {
- Element purposeEle = doc.createElement(XmlUtils.OD_TAG_ITEM);
- purposeEle.setAttribute(XmlUtils.OD_ATTR_VALUE, String.valueOf(purpose.getValue()));
- purposesEle.appendChild(purposeEle);
- }
- dataTypeEle.appendChild(purposesEle);
+ dataTypeEle.appendChild(
+ XmlUtils.createOdArray(
+ doc,
+ XmlUtils.OD_TAG_INT_ARRAY,
+ XmlUtils.OD_NAME_PURPOSES,
+ this.getPurposeSet().stream()
+ .map(p -> String.valueOf(p.getValue()))
+ .toList()));
}
maybeAddBoolToOdElement(
@@ -162,7 +155,7 @@ public class DataType implements AslMarshallable {
this.getIsSharingOptional(),
XmlUtils.OD_NAME_IS_SHARING_OPTIONAL);
maybeAddBoolToOdElement(doc, dataTypeEle, this.getEphemeral(), XmlUtils.OD_NAME_EPHEMERAL);
- return List.of(dataTypeEle);
+ return XmlUtils.listOf(dataTypeEle);
}
private static void maybeAddBoolToOdElement(
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataTypeFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataTypeFactory.java
index e3d1587d860c..bfa330334487 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataTypeFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataTypeFactory.java
@@ -34,13 +34,10 @@ public class DataTypeFactory implements AslMarshallableFactory<DataType> {
.map(DataType.Purpose::forString)
.collect(Collectors.toUnmodifiableSet());
Boolean isCollectionOptional =
- XmlUtils.fromString(
- hrDataTypeEle.getAttribute(XmlUtils.HR_ATTR_IS_COLLECTION_OPTIONAL));
+ XmlUtils.getBoolAttr(hrDataTypeEle, XmlUtils.HR_ATTR_IS_COLLECTION_OPTIONAL);
Boolean isSharingOptional =
- XmlUtils.fromString(
- hrDataTypeEle.getAttribute(XmlUtils.HR_ATTR_IS_SHARING_OPTIONAL));
- Boolean ephemeral =
- XmlUtils.fromString(hrDataTypeEle.getAttribute(XmlUtils.HR_ATTR_EPHEMERAL));
+ XmlUtils.getBoolAttr(hrDataTypeEle, XmlUtils.HR_ATTR_IS_SHARING_OPTIONAL);
+ Boolean ephemeral = XmlUtils.getBoolAttr(hrDataTypeEle, XmlUtils.HR_ATTR_EPHEMERAL);
return new DataType(
dataTypeName, purposeSet, isCollectionOptional, isSharingOptional, ephemeral);
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DeveloperInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DeveloperInfo.java
new file mode 100644
index 000000000000..44a5b129e428
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DeveloperInfo.java
@@ -0,0 +1,140 @@
+/*
+ * 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 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);
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DeveloperInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DeveloperInfoFactory.java
new file mode 100644
index 000000000000..4961892b10c3
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DeveloperInfoFactory.java
@@ -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.asllib;
+
+import com.android.asllib.util.AslgenUtil;
+import com.android.asllib.util.MalformedXmlException;
+
+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);
+ String email = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_EMAIL);
+ String address = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_ADDRESS);
+ String countryRegion =
+ XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_COUNTRY_REGION);
+ DeveloperInfo.DeveloperRelationship developerRelationship =
+ DeveloperInfo.DeveloperRelationship.forString(
+ XmlUtils.getStringAttr(
+ developerInfoEle, XmlUtils.HR_ATTR_DEVELOPER_RELATIONSHIP));
+ 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);
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabels.java
index f06522fc2a5c..40ef48dc5334 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabels.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabels.java
@@ -47,7 +47,11 @@ public class SafetyLabels implements AslMarshallable {
public List<Element> toOdDomElements(Document doc) {
Element safetyLabelsEle =
XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_SAFETY_LABELS);
- XmlUtils.appendChildren(safetyLabelsEle, mDataLabels.toOdDomElements(doc));
- return List.of(safetyLabelsEle);
+ safetyLabelsEle.appendChild(
+ XmlUtils.createOdLongEle(doc, XmlUtils.OD_NAME_VERSION, mVersion));
+ if (mDataLabels != null) {
+ XmlUtils.appendChildren(safetyLabelsEle, mDataLabels.toOdDomElements(doc));
+ }
+ return XmlUtils.listOf(safetyLabelsEle);
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabelsFactory.java
index 80b9f5783b9d..ab81b1d56033 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabelsFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabelsFactory.java
@@ -16,6 +16,7 @@
package com.android.asllib;
+import com.android.asllib.util.AslgenUtil;
import com.android.asllib.util.MalformedXmlException;
import org.w3c.dom.Element;
@@ -28,18 +29,16 @@ public class SafetyLabelsFactory implements AslMarshallableFactory<SafetyLabels>
@Override
public SafetyLabels createFromHrElements(List<Element> elements) throws MalformedXmlException {
Element safetyLabelsEle = XmlUtils.getSingleElement(elements);
- Long version;
- try {
- version = Long.parseLong(safetyLabelsEle.getAttribute(XmlUtils.HR_ATTR_VERSION));
- } catch (Exception e) {
- throw new IllegalArgumentException(
- "Malformed or missing required version in safety labels.");
+ if (safetyLabelsEle == null) {
+ AslgenUtil.logI("No SafetyLabels found in hr format.");
+ return null;
}
+ long version = XmlUtils.tryGetVersion(safetyLabelsEle);
DataLabels dataLabels =
new DataLabelsFactory()
.createFromHrElements(
- List.of(
+ XmlUtils.listOf(
XmlUtils.getSingleChildElement(
safetyLabelsEle, XmlUtils.HR_TAG_DATA_LABELS)));
return new SafetyLabels(version, dataLabels);
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SystemAppSafetyLabel.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SystemAppSafetyLabel.java
new file mode 100644
index 000000000000..93d9c2b080c5
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SystemAppSafetyLabel.java
@@ -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.asllib;
+
+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 String mUrl;
+
+ public SystemAppSafetyLabel(String url) {
+ this.mUrl = url;
+ }
+
+ /** Returns the system app safety label URL. */
+ public String getUrl() {
+ return mUrl;
+ }
+
+ /** 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.createOdStringEle(doc, XmlUtils.OD_NAME_URL, mUrl));
+ return XmlUtils.listOf(systemAppSafetyLabelEle);
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SystemAppSafetyLabelFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SystemAppSafetyLabelFactory.java
new file mode 100644
index 000000000000..c8c1c7beba24
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SystemAppSafetyLabelFactory.java
@@ -0,0 +1,41 @@
+/*
+ * 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.util.AslgenUtil;
+import com.android.asllib.util.MalformedXmlException;
+
+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;
+ }
+
+ String url = XmlUtils.getStringAttr(systemAppSafetyLabelEle, XmlUtils.HR_ATTR_URL);
+ return new SystemAppSafetyLabel(url);
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/TransparencyInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/TransparencyInfo.java
new file mode 100644
index 000000000000..88717b9568b8
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/TransparencyInfo.java
@@ -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.asllib;
+
+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);
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/TransparencyInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/TransparencyInfoFactory.java
new file mode 100644
index 000000000000..13a7eb62fedd
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/TransparencyInfoFactory.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;
+
+import com.android.asllib.util.AslgenUtil;
+import com.android.asllib.util.MalformedXmlException;
+
+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);
+ }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/XmlUtils.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/XmlUtils.java
index cedaf9374cd4..cc8fe79cb579 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/XmlUtils.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/XmlUtils.java
@@ -23,16 +23,27 @@ import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
public class XmlUtils {
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_DATA_ACCESSED = "data-accessed";
public static final String HR_TAG_DATA_COLLECTED = "data-collected";
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";
@@ -40,16 +51,55 @@ public class XmlUtils {
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_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_SYSTEM_APP_SAFETY_LABEL = "system_app_safety_label";
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";
@@ -75,17 +125,39 @@ public class XmlUtils {
public static Element getSingleChildElement(Element parentEle, String tagName)
throws MalformedXmlException {
var elements = parentEle.getElementsByTagName(tagName);
- return getSingleElement(elements, tagName);
+ return getSingleElement(elements, tagName, true);
+ }
+
+ /**
+ * Gets the single {@link Element} within {@param parentEle} and having the {@param tagName}.
+ */
+ public static Element getSingleChildElement(Element parentEle, String tagName, boolean required)
+ throws MalformedXmlException {
+ var elements = parentEle.getElementsByTagName(tagName);
+ return getSingleElement(elements, tagName, required);
}
/** Gets the single {@link Element} from {@param elements} */
public static Element getSingleElement(NodeList elements, String tagName)
throws MalformedXmlException {
- if (elements.getLength() != 1) {
+ return getSingleElement(elements, tagName, true);
+ }
+
+ /** Gets the single {@link Element} from {@param elements} */
+ public static Element getSingleElement(NodeList elements, String tagName, boolean required)
+ throws MalformedXmlException {
+ if (elements.getLength() > 1) {
throw new MalformedXmlException(
String.format(
"Expected 1 element \"%s\" in NodeList but got %s.",
tagName, elements.getLength()));
+ } else if (elements.getLength() == 0) {
+ if (required) {
+ throw new MalformedXmlException(
+ String.format("Found no element \"%s\" in NodeList.", tagName));
+ } else {
+ return null;
+ }
}
var elementAsNode = elements.item(0);
if (!(elementAsNode instanceof Element)) {
@@ -124,7 +196,7 @@ public class XmlUtils {
}
/** Gets the Boolean from the String value. */
- public static Boolean fromString(String s) {
+ private static Boolean fromString(String s) {
if (s == null) {
return null;
}
@@ -151,8 +223,86 @@ public class XmlUtils {
return ele;
}
+ /** 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) {
+ long version;
+ try {
+ version = Long.parseLong(ele.getAttribute(XmlUtils.HR_ATTR_VERSION));
+ } catch (Exception e) {
+ throw new IllegalArgumentException(
+ String.format(
+ "Malformed or missing required version in: %s", ele.getTagName()));
+ }
+ return version;
+ }
+
+ /** Gets an optional Boolean attribute. */
+ public static Boolean getBoolAttr(Element ele, String attrName) {
+ return XmlUtils.fromString(ele.getAttribute(attrName));
+ }
+
+ /** 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;
+ }
+
+ /**
+ * 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/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/test/java/com/android/aslgen/AslgenTests.java b/tools/app_metadata_bundles/src/test/java/com/android/aslgen/AslgenTests.java
index cea22a2178b7..3026f8bec2ed 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/aslgen/AslgenTests.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/aslgen/AslgenTests.java
@@ -19,6 +19,7 @@ package com.android.aslgen;
import static org.junit.Assert.assertEquals;
import com.android.asllib.AndroidSafetyLabel;
+import com.android.asllib.AslConverter;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -73,9 +74,8 @@ public class AslgenTests {
getClass().getClassLoader().getResourceAsStream(odPath.toString());
String odContents = new String(odStream.readAllBytes(), StandardCharsets.UTF_8);
AndroidSafetyLabel asl =
- AndroidSafetyLabel.readFromString(
- hrContents, AndroidSafetyLabel.Format.HUMAN_READABLE);
- String out = asl.getXmlAsString(AndroidSafetyLabel.Format.ON_DEVICE);
+ AslConverter.readFromString(hrContents, AslConverter.Format.HUMAN_READABLE);
+ String out = AslConverter.getXmlAsString(asl, AslConverter.Format.ON_DEVICE);
System.out.println("out: " + out);
assertEquals(getFormattedXml(out), getFormattedXml(odContents));