Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9d769347 authored by Max Loh's avatar Max Loh
Browse files

ASL version-based validation of required and unexpected fields, part 1

Asl objects were decoupled from AslMarshallable because not all Asl objects follow the same pattern. Also added version mapping logic, which maps a version number to the required or recognized fields for that version for each object. These can be updated as needed as future versions are released.

Bug: 350566067
Test: Unit tests
Flag: NONE (Command-line tool which doesn't affect Android functionality)
Change-Id: Ica0d3d6cb192d1663f9571a42c088b312c94c21c
parent b283f3d3
Loading
Loading
Loading
Loading
+4 −10
Original line number Diff line number Diff line
@@ -62,13 +62,11 @@ public class AslConverter {
                        XmlUtils.getSingleChildElement(
                                document, XmlUtils.HR_TAG_APP_METADATA_BUNDLES, true);

                return new AndroidSafetyLabelFactory()
                        .createFromHrElements(XmlUtils.listOf(appMetadataBundles));
                return new AndroidSafetyLabelFactory().createFromHrElement(appMetadataBundles);
            case ON_DEVICE:
                Element bundleEle =
                        XmlUtils.getSingleChildElement(document, XmlUtils.OD_TAG_BUNDLE, true);
                return new AndroidSafetyLabelFactory()
                        .createFromOdElements(XmlUtils.listOf(bundleEle));
                return new AndroidSafetyLabelFactory().createFromOdElement(bundleEle);
            default:
                throw new IllegalStateException("Unrecognized input format.");
        }
@@ -91,14 +89,10 @@ public class AslConverter {

        switch (format) {
            case HUMAN_READABLE:
                for (var child : asl.toHrDomElements(document)) {
                    document.appendChild(child);
                }
                document.appendChild(asl.toHrDomElement(document));
                break;
            case ON_DEVICE:
                for (var child : asl.toOdDomElements(document)) {
                    document.appendChild(child);
                }
                document.appendChild(asl.toOdDomElement(document));
                break;
            default:
                throw new IllegalStateException("Unrecognized input format.");
+10 −14
Original line number Diff line number Diff line
@@ -21,8 +21,6 @@ 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;
@@ -46,36 +44,34 @@ public class AndroidSafetyLabel implements AslMarshallable {
    }

    /** Creates an on-device DOM element from an {@link AndroidSafetyLabel} */
    @Override
    public List<Element> toOdDomElements(Document doc) {
    public Element toOdDomElement(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));
            aslEle.appendChild(mSafetyLabels.toOdDomElement(doc));
        }
        if (mSystemAppSafetyLabel != null) {
            XmlUtils.appendChildren(aslEle, mSystemAppSafetyLabel.toOdDomElements(doc));
            aslEle.appendChild(mSystemAppSafetyLabel.toOdDomElement(doc));
        }
        if (mTransparencyInfo != null) {
            XmlUtils.appendChildren(aslEle, mTransparencyInfo.toOdDomElements(doc));
            aslEle.appendChild(mTransparencyInfo.toOdDomElement(doc));
        }
        return XmlUtils.listOf(aslEle);
        return aslEle;
    }

    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
    @Override
    public List<Element> toHrDomElements(Document doc) {
    public Element toHrDomElement(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));
            aslEle.appendChild(mSafetyLabels.toHrDomElement(doc));
        }
        if (mSystemAppSafetyLabel != null) {
            XmlUtils.appendChildren(aslEle, mSystemAppSafetyLabel.toHrDomElements(doc));
            aslEle.appendChild(mSystemAppSafetyLabel.toHrDomElement(doc));
        }
        if (mTransparencyInfo != null) {
            XmlUtils.appendChildren(aslEle, mTransparencyInfo.toHrDomElements(doc));
            aslEle.appendChild(mTransparencyInfo.toHrDomElement(doc));
        }
        return XmlUtils.listOf(aslEle);
        return aslEle;
    }
}
+74 −22
Original line number Diff line number Diff line
@@ -21,65 +21,117 @@ import com.android.asllib.util.XmlUtils;

import org.w3c.dom.Element;

import java.util.List;
import java.util.Map;
import java.util.Set;

public class AndroidSafetyLabelFactory implements AslMarshallableFactory<AndroidSafetyLabel> {
    private final Map<Long, Set<String>> mRecognizedHrAttrs =
            Map.ofEntries(Map.entry(1L, Set.of(XmlUtils.HR_ATTR_VERSION)));
    private final Map<Long, Set<String>> mRequiredHrAttrs =
            Map.ofEntries(Map.entry(1L, Set.of(XmlUtils.HR_ATTR_VERSION)));
    private final Map<Long, Set<String>> mRecognizedHrEles =
            Map.ofEntries(
                    Map.entry(
                            1L,
                            Set.of(
                                    XmlUtils.HR_TAG_SYSTEM_APP_SAFETY_LABEL,
                                    XmlUtils.HR_TAG_SAFETY_LABELS,
                                    XmlUtils.HR_TAG_TRANSPARENCY_INFO)));
    private final Map<Long, Set<String>> mRequiredHrEles =
            Map.ofEntries(
                    Map.entry(1L, Set.of()),
                    Map.entry(
                            2L,
                            Set.of(
                                    XmlUtils.HR_TAG_SYSTEM_APP_SAFETY_LABEL,
                                    XmlUtils.HR_TAG_TRANSPARENCY_INFO)));
    private final Map<Long, Set<String>> mRecognizedOdEleNames =
            Map.ofEntries(
                    Map.entry(
                            1L,
                            Set.of(
                                    XmlUtils.OD_NAME_VERSION,
                                    XmlUtils.OD_NAME_SAFETY_LABELS,
                                    XmlUtils.OD_NAME_SYSTEM_APP_SAFETY_LABEL,
                                    XmlUtils.OD_NAME_TRANSPARENCY_INFO)));
    private final Map<Long, Set<String>> mRequiredOdEleNames =
            Map.ofEntries(
                    Map.entry(1L, Set.of(XmlUtils.OD_NAME_VERSION)),
                    Map.entry(
                            2L,
                            Set.of(
                                    XmlUtils.OD_NAME_VERSION,
                                    XmlUtils.OD_NAME_SYSTEM_APP_SAFETY_LABEL,
                                    XmlUtils.OD_NAME_TRANSPARENCY_INFO)));

    /** Creates an {@link AndroidSafetyLabel} from human-readable DOM element */
    @Override
    public AndroidSafetyLabel createFromHrElements(List<Element> appMetadataBundles)
    public AndroidSafetyLabel createFromHrElement(Element appMetadataBundlesEle)
            throws MalformedXmlException {
        Element appMetadataBundlesEle = XmlUtils.getSingleElement(appMetadataBundles);
        long version = XmlUtils.tryGetVersion(appMetadataBundlesEle);
        XmlUtils.throwIfExtraneousAttributes(
                appMetadataBundlesEle, XmlUtils.getMostRecentVersion(mRecognizedHrAttrs, version));
        XmlUtils.throwIfExtraneousChildrenHr(
                appMetadataBundlesEle, XmlUtils.getMostRecentVersion(mRecognizedHrEles, version));

        Element safetyLabelsEle =
                XmlUtils.getSingleChildElement(
                        appMetadataBundlesEle, XmlUtils.HR_TAG_SAFETY_LABELS, false);
                        appMetadataBundlesEle,
                        XmlUtils.HR_TAG_SAFETY_LABELS,
                        XmlUtils.getMostRecentVersion(mRequiredHrEles, version));
        SafetyLabels safetyLabels =
                new SafetyLabelsFactory().createFromHrElements(XmlUtils.listOf(safetyLabelsEle));
                new SafetyLabelsFactory().createFromHrElement(safetyLabelsEle, version);

        Element systemAppSafetyLabelEle =
                XmlUtils.getSingleChildElement(
                        appMetadataBundlesEle, XmlUtils.HR_TAG_SYSTEM_APP_SAFETY_LABEL, false);
                        appMetadataBundlesEle,
                        XmlUtils.HR_TAG_SYSTEM_APP_SAFETY_LABEL,
                        XmlUtils.getMostRecentVersion(mRequiredHrEles, version));
        SystemAppSafetyLabel systemAppSafetyLabel =
                new SystemAppSafetyLabelFactory()
                        .createFromHrElements(XmlUtils.listOf(systemAppSafetyLabelEle));
                        .createFromHrElement(systemAppSafetyLabelEle, version);

        Element transparencyInfoEle =
                XmlUtils.getSingleChildElement(
                        appMetadataBundlesEle, XmlUtils.HR_TAG_TRANSPARENCY_INFO, false);
                        appMetadataBundlesEle,
                        XmlUtils.HR_TAG_TRANSPARENCY_INFO,
                        XmlUtils.getMostRecentVersion(mRequiredHrEles, version));
        TransparencyInfo transparencyInfo =
                new TransparencyInfoFactory()
                        .createFromHrElements(XmlUtils.listOf(transparencyInfoEle));
                new TransparencyInfoFactory().createFromHrElement(transparencyInfoEle, version);

        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);
    public AndroidSafetyLabel createFromOdElement(Element bundleEle) throws MalformedXmlException {
        Long version = XmlUtils.getOdLongEle(bundleEle, XmlUtils.OD_NAME_VERSION, true);
        XmlUtils.throwIfExtraneousChildrenOd(
                bundleEle, XmlUtils.getMostRecentVersion(mRecognizedOdEleNames, version));

        Element safetyLabelsEle =
                XmlUtils.getOdPbundleWithName(bundleEle, XmlUtils.OD_NAME_SAFETY_LABELS, false);
                XmlUtils.getOdPbundleWithName(
                        bundleEle,
                        XmlUtils.OD_NAME_SAFETY_LABELS,
                        XmlUtils.getMostRecentVersion(mRequiredOdEleNames, version));
        SafetyLabels safetyLabels =
                new SafetyLabelsFactory().createFromOdElements(XmlUtils.listOf(safetyLabelsEle));
                new SafetyLabelsFactory().createFromOdElement(safetyLabelsEle, version);

        Element systemAppSafetyLabelEle =
                XmlUtils.getOdPbundleWithName(
                        bundleEle, XmlUtils.OD_NAME_SYSTEM_APP_SAFETY_LABEL, false);
                        bundleEle,
                        XmlUtils.OD_NAME_SYSTEM_APP_SAFETY_LABEL,
                        XmlUtils.getMostRecentVersion(mRequiredOdEleNames, version));
        SystemAppSafetyLabel systemAppSafetyLabel =
                new SystemAppSafetyLabelFactory()
                        .createFromOdElements(XmlUtils.listOf(systemAppSafetyLabelEle));
                        .createFromOdElement(systemAppSafetyLabelEle, version);

        Element transparencyInfoEle =
                XmlUtils.getOdPbundleWithName(bundleEle, XmlUtils.OD_NAME_TRANSPARENCY_INFO, false);
                XmlUtils.getOdPbundleWithName(
                        bundleEle,
                        XmlUtils.OD_NAME_TRANSPARENCY_INFO,
                        XmlUtils.getMostRecentVersion(mRequiredOdEleNames, version));
        TransparencyInfo transparencyInfo =
                new TransparencyInfoFactory()
                        .createFromOdElements(XmlUtils.listOf(transparencyInfoEle));
                new TransparencyInfoFactory().createFromOdElement(transparencyInfoEle, version);

        return new AndroidSafetyLabel(
                version, systemAppSafetyLabel, safetyLabels, transparencyInfo);
+153 −15
Original line number Diff line number Diff line
@@ -25,36 +25,107 @@ import java.util.List;

/** AppInfo representation */
public class AppInfo implements AslMarshallable {
    private final Boolean mApsCompliant;
    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;

    private final Boolean mApsCompliant;
    private final String mDeveloperId;
    private final String mApplicationId;

    // private final String mPrivacyPolicy;
    // private final List<String> mFirstPartyEndpoints;
    // private final List<String> mServiceProviderEndpoints;

    public AppInfo(
            Boolean apsCompliant,
            String title,
            String description,
            Boolean containsAds,
            Boolean obeyAps,
            Boolean adsFingerprinting,
            Boolean securityFingerprinting,
            String privacyPolicy,
            List<String> securityEndpoints,
            List<String> firstPartyEndpoints,
            List<String> serviceProviderEndpoints) {
        this.mApsCompliant = apsCompliant;
            List<String> serviceProviderEndpoints,
            String category,
            String email,
            String website,
            Boolean apsCompliant,
            String developerId,
            String applicationId) {
        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;
        this.mApsCompliant = apsCompliant;
        this.mDeveloperId = developerId;
        this.mApplicationId = applicationId;
    }

    /** Creates an on-device DOM element from the {@link SafetyLabels}. */
    @Override
    public List<Element> toOdDomElements(Document doc) {
    public Element toOdDomElement(Document doc) {
        Element appInfoEle = XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_APP_INFO);
        if (this.mApsCompliant != null) {

        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_APS_COMPLIANT, mApsCompliant));
                            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_ENDPOINTS,
                            mSecurityEndpoints));
        }
        if (this.mFirstPartyEndpoints != null) {
            appInfoEle.appendChild(
                    XmlUtils.createOdArray(
@@ -71,27 +142,88 @@ public class AppInfo implements AslMarshallable {
                            XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINTS,
                            mServiceProviderEndpoints));
        }
        return XmlUtils.listOf(appInfoEle);
        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));
        }

        if (this.mApsCompliant != null) {
            appInfoEle.appendChild(
                    XmlUtils.createOdBooleanEle(
                            doc, XmlUtils.OD_NAME_APS_COMPLIANT, mApsCompliant));
        }
        if (this.mDeveloperId != null) {
            appInfoEle.appendChild(
                    XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_DEVELOPER_ID, mDeveloperId));
        }
        if (this.mApplicationId != null) {
            appInfoEle.appendChild(
                    XmlUtils.createOdStringEle(
                            doc, XmlUtils.OD_NAME_APPLICATION_ID, mApplicationId));
        }
        return appInfoEle;
    }

    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
    @Override
    public List<Element> toHrDomElements(Document doc) {
    public Element toHrDomElement(Document doc) {
        Element appInfoEle = doc.createElement(XmlUtils.HR_TAG_APP_INFO);
        if (this.mApsCompliant != null) {

        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_APS_COMPLIANT, String.valueOf(this.mApsCompliant));
                    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.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);
        }

        if (this.mApsCompliant != null) {
            appInfoEle.setAttribute(
                    XmlUtils.HR_ATTR_APS_COMPLIANT, String.valueOf(this.mApsCompliant));
        }
        if (this.mFirstPartyEndpoints != null) {
            appInfoEle.appendChild(
                    XmlUtils.createHrArray(
                            doc, XmlUtils.HR_TAG_FIRST_PARTY_ENDPOINTS, mFirstPartyEndpoints));
        }

        if (this.mServiceProviderEndpoints != null) {
            appInfoEle.appendChild(
                    XmlUtils.createHrArray(
@@ -99,7 +231,13 @@ public class AppInfo implements AslMarshallable {
                            XmlUtils.HR_TAG_SERVICE_PROVIDER_ENDPOINTS,
                            mServiceProviderEndpoints));
        }
        if (this.mDeveloperId != null) {
            appInfoEle.setAttribute(XmlUtils.HR_ATTR_DEVELOPER_ID, this.mDeveloperId);
        }
        if (this.mApplicationId != null) {
            appInfoEle.setAttribute(XmlUtils.HR_ATTR_APPLICATION_ID, this.mApplicationId);
        }

        return XmlUtils.listOf(appInfoEle);
        return appInfoEle;
    }
}
+200 −27

File changed.

Preview size limit exceeded, changes collapsed.

Loading