Merge "Introduce per-user InputMethodSettings cache (2nd try)" into main
diff --git a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
index 13355f3..43ff7b6 100644
--- a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
+++ b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
@@ -47,7 +47,7 @@
         android:layout_marginBottom="@dimen/bluetooth_dialog_layout_margin"
         android:ellipsize="end"
         android:gravity="center_vertical|center_horizontal"
-        android:maxLines="1"
+        android:maxLines="2"
         android:text="@string/quick_settings_bluetooth_tile_subtitle"
         android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
         app:layout_constraintEnd_toEndOf="parent"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index af661aa..2fed457 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -687,9 +687,9 @@
     <!-- QuickSettings: Bluetooth auto on tomorrow [CHAR LIMIT=NONE]-->
     <string name="turn_on_bluetooth_auto_tomorrow">Automatically turn on again tomorrow</string>
     <!-- QuickSettings: Bluetooth auto on info text when disabled [CHAR LIMIT=NONE]-->
-    <string name="turn_on_bluetooth_auto_info_disabled">Features like Quick Share, Find My Device, and device location use Bluetooth</string>
+    <string name="turn_on_bluetooth_auto_info_disabled">Features like Quick Share and Find My Device use Bluetooth</string>
     <!-- QuickSettings: Bluetooth auto on info text when enabled [CHAR LIMIT=NONE]-->
-    <string name="turn_on_bluetooth_auto_info_enabled">Bluetooth will turn on tomorrow at 5 AM</string>
+    <string name="turn_on_bluetooth_auto_info_enabled">Bluetooth will turn on tomorrow morning</string>
 
     <!-- QuickSettings: Bluetooth secondary label for the battery level of a connected device [CHAR LIMIT=20]-->
     <string name="quick_settings_bluetooth_secondary_label_battery_level"><xliff:g id="battery_level_as_percentage">%s</xliff:g> battery</string>
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8022eb3..4aae7d1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4437,8 +4437,16 @@
         final boolean clearPendingIntentsForStoppedApp = (android.content.pm.Flags.stayStopped()
                 && packageStateStopped);
         if (packageName == null || uninstalling || clearPendingIntentsForStoppedApp) {
+            final int cancelReason;
+            if (packageName == null) {
+                cancelReason = PendingIntentRecord.CANCEL_REASON_USER_STOPPED;
+            } else if (uninstalling) {
+                cancelReason = PendingIntentRecord.CANCEL_REASON_OWNER_UNINSTALLED;
+            } else {
+                cancelReason = PendingIntentRecord.CANCEL_REASON_OWNER_FORCE_STOPPED;
+            }
             didSomething |= mPendingIntentController.removePendingIntentsForPackage(
-                    packageName, userId, appId, doit);
+                    packageName, userId, appId, doit, cancelReason);
         }
 
         if (doit) {
diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java
index fb0d695..f336120 100644
--- a/services/core/java/com/android/server/am/PendingIntentController.java
+++ b/services/core/java/com/android/server/am/PendingIntentController.java
@@ -22,6 +22,8 @@
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_OWNER_CANCELED;
+import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_SUPERSEDED;
 
 import android.annotation.Nullable;
 import android.app.Activity;
@@ -54,6 +56,7 @@
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.AlarmManagerInternal;
 import com.android.server.LocalServices;
+import com.android.server.am.PendingIntentRecord.CancellationReason;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.SafeActivityOptions;
 
@@ -191,7 +194,7 @@
                     }
                     return rec;
                 }
-                makeIntentSenderCanceled(rec);
+                makeIntentSenderCanceled(rec, CANCEL_REASON_SUPERSEDED);
                 mIntentSenderRecords.remove(key);
                 decrementUidStatLocked(rec);
             }
@@ -206,7 +209,7 @@
     }
 
     boolean removePendingIntentsForPackage(String packageName, int userId, int appId,
-            boolean doIt) {
+            boolean doIt, @CancellationReason int cancelReason) {
 
         boolean didSomething = false;
         synchronized (mLock) {
@@ -256,7 +259,7 @@
                 }
                 didSomething = true;
                 it.remove();
-                makeIntentSenderCanceled(pir);
+                makeIntentSenderCanceled(pir, cancelReason);
                 decrementUidStatLocked(pir);
                 if (pir.key.activity != null) {
                     final Message m = PooledLambda.obtainMessage(
@@ -289,13 +292,14 @@
             } catch (RemoteException e) {
                 throw new SecurityException(e);
             }
-            cancelIntentSender(rec, true);
+            cancelIntentSender(rec, true, CANCEL_REASON_OWNER_CANCELED);
         }
     }
 
-    public void cancelIntentSender(PendingIntentRecord rec, boolean cleanActivity) {
+    public void cancelIntentSender(PendingIntentRecord rec, boolean cleanActivity,
+            @CancellationReason int cancelReason) {
         synchronized (mLock) {
-            makeIntentSenderCanceled(rec);
+            makeIntentSenderCanceled(rec, cancelReason);
             mIntentSenderRecords.remove(rec.key);
             decrementUidStatLocked(rec);
             if (cleanActivity && rec.key.activity != null) {
@@ -359,8 +363,10 @@
         }
     }
 
-    private void makeIntentSenderCanceled(PendingIntentRecord rec) {
+    private void makeIntentSenderCanceled(PendingIntentRecord rec,
+            @CancellationReason int cancelReason) {
         rec.canceled = true;
+        rec.cancelReason = cancelReason;
         final RemoteCallbackList<IResultReceiver> callbacks = rec.detachCancelListenersLocked();
         if (callbacks != null) {
             final Message m = PooledLambda.obtainMessage(
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 95e130e..da45a77 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -16,11 +16,13 @@
 
 package com.android.server.am;
 
+import static android.app.ActivityManager.PROCESS_STATE_TOP;
 import static android.app.ActivityManager.START_SUCCESS;
 
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
+import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.app.ActivityManager;
@@ -51,11 +53,15 @@
 import android.util.Slog;
 import android.util.TimeUtils;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.modules.expresslog.Counter;
 import com.android.server.wm.SafeActivityOptions;
 
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 import java.util.Objects;
 
@@ -71,12 +77,35 @@
     public static final int FLAG_BROADCAST_SENDER = 1 << 1;
     public static final int FLAG_SERVICE_SENDER = 1 << 2;
 
+    public static final int CANCEL_REASON_NULL = 0;
+    public static final int CANCEL_REASON_USER_STOPPED = 1 << 0;
+    public static final int CANCEL_REASON_OWNER_UNINSTALLED = 1 << 1;
+    public static final int CANCEL_REASON_OWNER_FORCE_STOPPED = 1 << 2;
+    public static final int CANCEL_REASON_OWNER_CANCELED = 1 << 3;
+    public static final int CANCEL_REASON_HOSTING_ACTIVITY_DESTROYED = 1 << 4;
+    public static final int CANCEL_REASON_SUPERSEDED = 1 << 5;
+    public static final int CANCEL_REASON_ONE_SHOT_SENT = 1 << 6;
+
+    @IntDef({
+            CANCEL_REASON_NULL,
+            CANCEL_REASON_USER_STOPPED,
+            CANCEL_REASON_OWNER_UNINSTALLED,
+            CANCEL_REASON_OWNER_FORCE_STOPPED,
+            CANCEL_REASON_OWNER_CANCELED,
+            CANCEL_REASON_HOSTING_ACTIVITY_DESTROYED,
+            CANCEL_REASON_SUPERSEDED,
+            CANCEL_REASON_ONE_SHOT_SENT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CancellationReason {}
+
     final PendingIntentController controller;
     final Key key;
     final int uid;
     public final WeakReference<PendingIntentRecord> ref;
     boolean sent = false;
     boolean canceled = false;
+    @CancellationReason int cancelReason = CANCEL_REASON_NULL;
     /**
      * Map IBinder to duration specified as Pair<Long, Integer>, Long is allowlist duration in
      * milliseconds, Integer is allowlist type defined at
@@ -419,12 +448,22 @@
         SafeActivityOptions mergedOptions = null;
         synchronized (controller.mLock) {
             if (canceled) {
+                if (cancelReason == CANCEL_REASON_OWNER_FORCE_STOPPED
+                        && controller.mAmInternal.getUidProcessState(callingUid)
+                                == PROCESS_STATE_TOP) {
+                    Counter.logIncrementWithUid(
+                            "app.value_force_stop_cancelled_pi_sent_from_top_per_caller",
+                            callingUid);
+                    Counter.logIncrementWithUid(
+                            "app.value_force_stop_cancelled_pi_sent_from_top_per_owner",
+                            uid);
+                }
                 return ActivityManager.START_CANCELED;
             }
 
             sent = true;
             if ((key.flags & PendingIntent.FLAG_ONE_SHOT) != 0) {
-                controller.cancelIntentSender(this, true);
+                controller.cancelIntentSender(this, true, CANCEL_REASON_ONE_SHOT_SENT);
             }
 
             finalIntent = key.requestIntent != null ? new Intent(key.requestIntent) : new Intent();
@@ -687,6 +726,21 @@
         }
     }
 
+    @VisibleForTesting
+    static String cancelReasonToString(@CancellationReason int cancelReason) {
+        return switch (cancelReason) {
+            case CANCEL_REASON_NULL -> "NULL";
+            case CANCEL_REASON_USER_STOPPED -> "USER_STOPPED";
+            case CANCEL_REASON_OWNER_UNINSTALLED -> "OWNER_UNINSTALLED";
+            case CANCEL_REASON_OWNER_FORCE_STOPPED -> "OWNER_FORCE_STOPPED";
+            case CANCEL_REASON_OWNER_CANCELED -> "OWNER_CANCELED";
+            case CANCEL_REASON_HOSTING_ACTIVITY_DESTROYED -> "HOSTING_ACTIVITY_DESTROYED";
+            case CANCEL_REASON_SUPERSEDED -> "SUPERSEDED";
+            case CANCEL_REASON_ONE_SHOT_SENT -> "ONE_SHOT_SENT";
+            default -> "UNKNOWN";
+        };
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("uid="); pw.print(uid);
                 pw.print(" packageName="); pw.print(key.packageName);
@@ -707,7 +761,8 @@
         }
         if (sent || canceled) {
             pw.print(prefix); pw.print("sent="); pw.print(sent);
-                    pw.print(" canceled="); pw.println(canceled);
+                    pw.print(" canceled="); pw.print(canceled);
+                    pw.print(" cancelReason="); pw.println(cancelReasonToString(cancelReason));
         }
         if (mAllowlistDuration != null) {
             pw.print(prefix);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 83745ed..42373aa 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4260,7 +4260,8 @@
                 PendingIntentRecord rec = apr.get();
                 if (rec != null) {
                     mAtmService.mPendingIntentController.cancelIntentSender(rec,
-                            false /* cleanActivity */);
+                            false /* cleanActivity */,
+                            PendingIntentRecord.CANCEL_REASON_HOSTING_ACTIVITY_DESTROYED);
                 }
             }
             pendingResults = null;
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java
index 783971a..89b48ba 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java
@@ -16,9 +16,18 @@
 
 package com.android.server.am;
 
+import static android.os.Process.INVALID_UID;
+
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_NULL;
+import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_ONE_SHOT_SENT;
+import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_OWNER_CANCELED;
+import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_OWNER_FORCE_STOPPED;
+import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_SUPERSEDED;
+import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_USER_STOPPED;
+import static com.android.server.am.PendingIntentRecord.cancelReasonToString;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -34,6 +43,7 @@
 import android.content.Intent;
 import android.content.pm.IPackageManager;
 import android.os.Looper;
+import android.os.UserHandle;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -54,6 +64,7 @@
     private static final String TEST_PACKAGE_NAME = "test-package-1";
     private static final String TEST_FEATURE_ID = "test-feature-1";
     private static final int TEST_CALLING_UID = android.os.Process.myUid();
+    private static final int TEST_USER_ID = 0;
     private static final Intent[] TEST_INTENTS = new Intent[]{new Intent("com.test.intent")};
 
     @Mock
@@ -92,7 +103,7 @@
 
     private PendingIntentRecord createPendingIntentRecord(int flags) {
         return mPendingIntentController.getIntentSender(ActivityManager.INTENT_SENDER_BROADCAST,
-                TEST_PACKAGE_NAME, TEST_FEATURE_ID, TEST_CALLING_UID, 0, null, null, 0,
+                TEST_PACKAGE_NAME, TEST_FEATURE_ID, TEST_CALLING_UID, TEST_USER_ID, null, null, 0,
                 TEST_INTENTS, null, flags, null);
     }
 
@@ -126,6 +137,54 @@
                 piCaptor.getValue().getTarget());
     }
 
+    @Test
+    public void testCancellationReason() {
+        {
+            final PendingIntentRecord pir = createPendingIntentRecord(0);
+            assertCancelReason(CANCEL_REASON_NULL, pir.cancelReason);
+        }
+
+        {
+            final PendingIntentRecord pir = createPendingIntentRecord(0);
+            mPendingIntentController.cancelIntentSender(pir);
+            assertCancelReason(CANCEL_REASON_OWNER_CANCELED, pir.cancelReason);
+        }
+
+        {
+            final PendingIntentRecord pir = createPendingIntentRecord(0);
+            createPendingIntentRecord(PendingIntent.FLAG_CANCEL_CURRENT);
+            assertCancelReason(CANCEL_REASON_SUPERSEDED, pir.cancelReason);
+        }
+
+        {
+            final PendingIntentRecord pir = createPendingIntentRecord(PendingIntent.FLAG_ONE_SHOT);
+            pir.send(0, null, null, null, null, null, null);
+            assertCancelReason(CANCEL_REASON_ONE_SHOT_SENT, pir.cancelReason);
+        }
+
+        {
+            final PendingIntentRecord pir = createPendingIntentRecord(0);
+            mPendingIntentController.removePendingIntentsForPackage(TEST_PACKAGE_NAME,
+                    TEST_USER_ID, UserHandle.getAppId(TEST_CALLING_UID), true,
+                    CANCEL_REASON_OWNER_FORCE_STOPPED);
+            assertCancelReason(CANCEL_REASON_OWNER_FORCE_STOPPED, pir.cancelReason);
+        }
+
+        {
+            final PendingIntentRecord pir = createPendingIntentRecord(0);
+            mPendingIntentController.removePendingIntentsForPackage(null,
+                    TEST_USER_ID, INVALID_UID, true,
+                    CANCEL_REASON_USER_STOPPED);
+            assertCancelReason(CANCEL_REASON_USER_STOPPED, pir.cancelReason);
+        }
+    }
+
+    private void assertCancelReason(int expectedReason, int actualReason) {
+        final String errMsg = "Expected: " + cancelReasonToString(expectedReason)
+                + "; Actual: " + cancelReasonToString(actualReason);
+        assertEquals(errMsg, expectedReason, actualReason);
+    }
+
     @After
     public void tearDown() {
         if (mMockingSession != null) {
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
index b98161d..191f38d 100644
--- 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
@@ -65,8 +65,10 @@
                 return new AndroidSafetyLabelFactory()
                         .createFromHrElements(XmlUtils.listOf(appMetadataBundles));
             case ON_DEVICE:
-                throw new IllegalArgumentException(
-                        "Parsing from on-device format is not supported at this time.");
+                Element bundleEle =
+                        XmlUtils.getSingleChildElement(document, XmlUtils.OD_TAG_BUNDLE, true);
+                return new AndroidSafetyLabelFactory()
+                        .createFromOdElements(XmlUtils.listOf(bundleEle));
             default:
                 throw new IllegalStateException("Unrecognized input format.");
         }
@@ -89,8 +91,10 @@
 
         switch (format) {
             case HUMAN_READABLE:
-                throw new IllegalArgumentException(
-                        "Outputting human-readable format is not supported at this time.");
+                for (var child : asl.toHrDomElements(document)) {
+                    document.appendChild(child);
+                }
+                break;
             case ON_DEVICE:
                 for (var child : asl.toOdDomElements(document)) {
                     document.appendChild(child);
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
index ecfad91..72140a1 100644
--- 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
@@ -65,6 +65,17 @@
     /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
     @Override
     public List<Element> toHrDomElements(Document doc) {
-        return List.of();
+        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
index 41ce6e55..c53cbbf 100644
--- 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
@@ -56,10 +56,32 @@
                 version, systemAppSafetyLabel, safetyLabels, transparencyInfo);
     }
 
-    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
+    /** Creates an {@link AndroidSafetyLabel} from on-device DOM elements */
     @Override
     public AndroidSafetyLabel createFromOdElements(List<Element> elements)
             throws MalformedXmlException {
-        return null;
+        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
index 21f328d..129733e 100644
--- 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
@@ -146,6 +146,55 @@
     /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
     @Override
     public List<Element> toHrDomElements(Document doc) {
-        return List.of();
+        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
index 6fcf637..c506961 100644
--- 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
@@ -35,15 +35,16 @@
             return null;
         }
 
-        String title = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_TITLE);
-        String description = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_DESCRIPTION);
+        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);
+        String privacyPolicy =
+                XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_PRIVACY_POLICY, true);
         List<String> securityEndpoints =
                 XmlUtils.getPipelineSplitAttr(
                         appInfoEle, XmlUtils.HR_ATTR_SECURITY_ENDPOINTS, true);
@@ -53,8 +54,8 @@
         List<String> serviceProviderEndpoints =
                 XmlUtils.getPipelineSplitAttr(
                         appInfoEle, XmlUtils.HR_ATTR_SERVICE_PROVIDER_ENDPOINTS, true);
-        String category = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_CATEGORY);
-        String email = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_EMAIL);
+        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(
@@ -76,6 +77,48 @@
     /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
     @Override
     public AppInfo createFromOdElements(List<Element> elements) throws MalformedXmlException {
-        return null;
+        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/DataCategory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java
index eb97554..d551953 100644
--- 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
@@ -63,6 +63,8 @@
     /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
     @Override
     public List<Element> toHrDomElements(Document doc) {
-        return List.of();
+        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/DataType.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java
index 02b7189..97304cb 100644
--- 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
@@ -163,7 +163,9 @@
     /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
     @Override
     public List<Element> toHrDomElements(Document doc) {
-        return List.of();
+        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(
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
index efdc8d0..94fad96 100644
--- 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
@@ -143,6 +143,31 @@
     /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
     @Override
     public List<Element> toHrDomElements(Document doc) {
-        return List.of();
+        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
index c3e7ac3..0f3b41c 100644
--- 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
@@ -34,15 +34,15 @@
             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 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);
+                XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_COUNTRY_REGION, true);
         DeveloperInfo.DeveloperRelationship developerRelationship =
                 DeveloperInfo.DeveloperRelationship.forString(
                         XmlUtils.getStringAttr(
-                                developerInfoEle, XmlUtils.HR_ATTR_DEVELOPER_RELATIONSHIP));
+                                developerInfoEle, XmlUtils.HR_ATTR_DEVELOPER_RELATIONSHIP, true));
         String website = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_WEBSITE, false);
         String appDeveloperRegistryId =
                 XmlUtils.getStringAttr(
@@ -61,6 +61,36 @@
     /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
     @Override
     public DeveloperInfo createFromOdElements(List<Element> elements) throws MalformedXmlException {
-        return null;
+        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
index 576820d..6af8071 100644
--- 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
@@ -74,6 +74,18 @@
     /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
     @Override
     public List<Element> toHrDomElements(Document doc) {
-        return List.of();
+        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
index 7e1838f..2644b43 100644
--- 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
@@ -66,6 +66,37 @@
     /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
     @Override
     public SafetyLabels createFromOdElements(List<Element> elements) throws MalformedXmlException {
-        return null;
+        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
index 437343b..48643ba 100644
--- 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
@@ -54,6 +54,13 @@
     /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
     @Override
     public List<Element> toHrDomElements(Document doc) {
-        return List.of();
+        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
index 9dc4712c..525a803 100644
--- 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
@@ -46,6 +46,15 @@
     @Override
     public SecurityLabels createFromOdElements(List<Element> elements)
             throws MalformedXmlException {
-        return null;
+        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
index f0ecf93..854c0d0 100644
--- 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
@@ -50,6 +50,9 @@
     /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
     @Override
     public List<Element> toHrDomElements(Document doc) {
-        return List.of();
+        Element systemAppSafetyLabelEle =
+                doc.createElement(XmlUtils.HR_TAG_SYSTEM_APP_SAFETY_LABEL);
+        systemAppSafetyLabelEle.setAttribute(XmlUtils.HR_ATTR_URL, mUrl);
+        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
index 5b7fe32..c8e22b6 100644
--- 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
@@ -36,7 +36,7 @@
             return null;
         }
 
-        String url = XmlUtils.getStringAttr(systemAppSafetyLabelEle, XmlUtils.HR_ATTR_URL);
+        String url = XmlUtils.getStringAttr(systemAppSafetyLabelEle, XmlUtils.HR_ATTR_URL, true);
         return new SystemAppSafetyLabel(url);
     }
 
@@ -44,6 +44,12 @@
     @Override
     public SystemAppSafetyLabel createFromOdElements(List<Element> elements)
             throws MalformedXmlException {
-        return null;
+        Element systemAppSafetyLabelEle = XmlUtils.getSingleElement(elements);
+        if (systemAppSafetyLabelEle == null) {
+            AslgenUtil.logI("No SystemAppSafetyLabel found in od format.");
+            return null;
+        }
+        String url = XmlUtils.getOdStringEle(systemAppSafetyLabelEle, XmlUtils.OD_NAME_URL, true);
+        return new SystemAppSafetyLabel(url);
     }
 }
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
index 229b002..d74f3f0 100644
--- 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
@@ -44,6 +44,8 @@
     /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
     @Override
     public List<Element> toHrDomElements(Document doc) {
-        return List.of();
+        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
index ac4d383..197e7aa 100644
--- 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
@@ -37,7 +37,7 @@
             return null;
         }
 
-        String url = XmlUtils.getStringAttr(ele, XmlUtils.HR_ATTR_URL);
+        String url = XmlUtils.getStringAttr(ele, XmlUtils.HR_ATTR_URL, true);
         return new ThirdPartyVerification(url);
     }
 
@@ -45,6 +45,13 @@
     @Override
     public ThirdPartyVerification createFromOdElements(List<Element> elements)
             throws MalformedXmlException {
-        return null;
+        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
index ce7ef16..6a8700a 100644
--- 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
@@ -61,6 +61,13 @@
     /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
     @Override
     public List<Element> toHrDomElements(Document doc) {
-        return List.of();
+        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
index 123de01..94c5640 100644
--- 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
@@ -54,6 +54,23 @@
     @Override
     public TransparencyInfo createFromOdElements(List<Element> elements)
             throws MalformedXmlException {
-        return null;
+        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/XmlUtils.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java
index 4f21b0c..1d54ead 100644
--- 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
@@ -320,6 +320,63 @@
         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 %s in %s.", nameName, ele.getTagName()));
+        }
+        if (longEles.isEmpty()) {
+            if (required) {
+                throw new MalformedXmlException(
+                        String.format("Found no %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 %s in %s.", nameName, ele.getTagName()));
+        }
+        if (eles.isEmpty()) {
+            if (required) {
+                throw new MalformedXmlException(
+                        String.format("Found no %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 {
@@ -379,7 +436,7 @@
                 throw new MalformedXmlException(
                         String.format("Found no %s in %s.", nameName, ele.getTagName()));
             }
-            return List.of();
+            return null;
         }
         Element intArrayEle = intArrayEles.get(0);
         List<Element> itemEles = XmlUtils.getChildrenByTagName(intArrayEle, XmlUtils.OD_TAG_ITEM);
@@ -390,6 +447,33 @@
         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 %s in %s.", nameName, ele.getTagName()));
+        }
+        if (arrayEles.isEmpty()) {
+            if (required) {
+                throw new MalformedXmlException(
+                        String.format("Found no %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.
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
index e2588d7..d2e0fc3 100644
--- 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
@@ -56,18 +56,35 @@
 
             InputStream hrStream =
                     getClass().getClassLoader().getResourceAsStream(hrPath.toString());
-            String hrContents = new String(hrStream.readAllBytes(), StandardCharsets.UTF_8);
+            String hrContents =
+                    TestUtils.getFormattedXml(
+                            new String(hrStream.readAllBytes(), StandardCharsets.UTF_8), false);
             InputStream odStream =
                     getClass().getClassLoader().getResourceAsStream(odPath.toString());
-            String odContents = new String(odStream.readAllBytes(), StandardCharsets.UTF_8);
-            AndroidSafetyLabel asl =
+            String odContents =
+                    TestUtils.getFormattedXml(
+                            new String(odStream.readAllBytes(), StandardCharsets.UTF_8), false);
+            AndroidSafetyLabel aslFromHr =
                     AslConverter.readFromString(hrContents, AslConverter.Format.HUMAN_READABLE);
-            String out = AslConverter.getXmlAsString(asl, AslConverter.Format.ON_DEVICE);
-            System.out.println("out: " + out);
+            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);
 
-            assertEquals(
-                    TestUtils.getFormattedXml(out, false),
-                    TestUtils.getFormattedXml(odContents, 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
index 0137007..61a7823 100644
--- 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
@@ -22,7 +22,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
-import org.w3c.dom.Document;
 
 @RunWith(JUnit4.class)
 public class AndroidSafetyLabelTest {
@@ -38,12 +37,9 @@
             "with-system-app-safety-label.xml";
     private static final String WITH_TRANSPARENCY_INFO_FILE_NAME = "with-transparency-info.xml";
 
-    private Document mDoc = null;
-
     @Before
     public void setUp() throws Exception {
         System.out.println("set up.");
-        mDoc = TestUtils.document();
     }
 
     /** Test for android safety label missing version. */
@@ -51,6 +47,7 @@
     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. */
@@ -58,6 +55,7 @@
     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. */
@@ -65,6 +63,7 @@
     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. */
@@ -72,6 +71,7 @@
     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. */
@@ -79,6 +79,7 @@
     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) {
@@ -86,12 +87,26 @@
                 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(
-                mDoc,
+                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
index a015e2e..9e91c6f 100644
--- 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
@@ -25,7 +25,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
-import org.w3c.dom.Document;
 
 import java.nio.file.Paths;
 import java.util.List;
@@ -48,19 +47,31 @@
                     "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";
 
-    private Document mDoc = null;
-
     /** 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.");
-        mDoc = TestUtils.document();
     }
 
     /** Test for all fields valid. */
@@ -68,6 +79,7 @@
     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. */
@@ -75,7 +87,7 @@
     public void testMissingRequiredFields() throws Exception {
         System.out.println("Starting testMissingRequiredFields");
         for (String reqField : REQUIRED_FIELD_NAMES) {
-            System.out.println("testing missing required field: " + reqField);
+            System.out.println("testing missing required field hr: " + reqField);
             var appInfoEle =
                     TestUtils.getElementsFromResource(
                             Paths.get(APP_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME));
@@ -85,6 +97,17 @@
                     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. */
@@ -96,12 +119,34 @@
                             Paths.get(APP_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME));
             ele.get(0).removeAttribute(optField);
             AppInfo appInfo = new AppInfoFactory().createFromHrElements(ele);
-            appInfo.toOdDomElements(mDoc);
+            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(
-                mDoc, new AppInfoFactory(), APP_INFO_HR_PATH, APP_INFO_OD_PATH, fileName);
+                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/DataCategoryTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataCategoryTest.java
index 822f175..ebb3186 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataCategoryTest.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataCategoryTest.java
@@ -22,7 +22,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
-import org.w3c.dom.Document;
 
 @RunWith(JUnit4.class)
 public class DataCategoryTest {
@@ -57,15 +56,12 @@
             "data-category-personal-unrecognized-type.xml";
     private static final String UNRECOGNIZED_CATEGORY_FILE_NAME = "data-category-unrecognized.xml";
 
-    private Document mDoc = null;
-
     /** 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.");
-        mDoc = TestUtils.document();
     }
 
     /** Test for data category personal. */
@@ -207,7 +203,7 @@
 
     private void testHrToOdDataCategory(String fileName) throws Exception {
         TestUtils.testHrToOd(
-                mDoc,
+                TestUtils.document(),
                 new DataCategoryFactory(),
                 DATA_CATEGORY_HR_PATH,
                 DATA_CATEGORY_OD_PATH,
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
index 6f6f254..2661726 100644
--- 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
@@ -22,7 +22,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
-import org.w3c.dom.Document;
 
 @RunWith(JUnit4.class)
 public class DataLabelsTest {
@@ -65,12 +64,9 @@
     private static final String UNRECOGNIZED_FILE_NAME = "data-category-unrecognized.xml";
     private static final String UNRECOGNIZED_TYPE_FILE_NAME = "data-category-unrecognized-type.xml";
 
-    private Document mDoc = null;
-
     @Before
     public void setUp() throws Exception {
         System.out.println("set up.");
-        mDoc = TestUtils.document();
     }
 
     /** Test for data labels accessed valid bool. */
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
index ff8346a..72e8d65 100644
--- 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
@@ -25,7 +25,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
-import org.w3c.dom.Document;
 
 import java.nio.file.Paths;
 import java.util.List;
@@ -36,19 +35,20 @@
     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";
 
-    private Document mDoc = null;
-
     /** 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.");
-        mDoc = TestUtils.document();
     }
 
     /** Test for all fields valid. */
@@ -56,6 +56,7 @@
     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. */
@@ -73,6 +74,18 @@
                     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. */
@@ -85,16 +98,35 @@
             developerInfoEle.get(0).removeAttribute(optField);
             DeveloperInfo developerInfo =
                     new DeveloperInfoFactory().createFromHrElements(developerInfoEle);
-            developerInfo.toOdDomElements(mDoc);
+            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(
-                mDoc,
+                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
index c52d6c8..bba6b54 100644
--- 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
@@ -22,7 +22,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
-import org.w3c.dom.Document;
 
 @RunWith(JUnit4.class)
 public class SafetyLabelsTest {
@@ -36,12 +35,9 @@
     private static final String WITH_THIRD_PARTY_VERIFICATION_FILE_NAME =
             "with-third-party-verification.xml";
 
-    private Document mDoc = null;
-
     @Before
     public void setUp() throws Exception {
         System.out.println("set up.");
-        mDoc = TestUtils.document();
     }
 
     /** Test for safety labels missing version. */
@@ -49,6 +45,7 @@
     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. */
@@ -56,6 +53,7 @@
     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. */
@@ -63,6 +61,7 @@
     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. */
@@ -70,6 +69,7 @@
     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. */
@@ -77,18 +77,32 @@
     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(
-                mDoc,
+                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
index c0d0d72..a940bc6 100644
--- 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
@@ -23,7 +23,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
-import org.w3c.dom.Document;
 
 import java.nio.file.Paths;
 import java.util.List;
@@ -35,18 +34,17 @@
 
     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";
 
-    private Document mDoc = null;
-
     /** 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.");
-        mDoc = TestUtils.document();
     }
 
     /** Test for all fields valid. */
@@ -54,6 +52,7 @@
     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. */
@@ -65,16 +64,33 @@
                             Paths.get(SECURITY_LABELS_HR_PATH, ALL_FIELDS_VALID_FILE_NAME));
             ele.get(0).removeAttribute(optField);
             SecurityLabels securityLabels = new SecurityLabelsFactory().createFromHrElements(ele);
-            securityLabels.toOdDomElements(mDoc);
+            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(
-                mDoc,
+                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
index 191091a..33c2764 100644
--- 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
@@ -22,7 +22,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
-import org.w3c.dom.Document;
 
 @RunWith(JUnit4.class)
 public class SystemAppSafetyLabelTest {
@@ -34,15 +33,12 @@
     private static final String VALID_FILE_NAME = "valid.xml";
     private static final String MISSING_URL_FILE_NAME = "missing-url.xml";
 
-    private Document mDoc = null;
-
     /** 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.");
-        mDoc = TestUtils.document();
     }
 
     /** Test for valid. */
@@ -50,6 +46,7 @@
     public void testValid() throws Exception {
         System.out.println("starting testValid.");
         testHrToOdSystemAppSafetyLabel(VALID_FILE_NAME);
+        testOdToHrSystemAppSafetyLabel(VALID_FILE_NAME);
     }
 
     /** Tests missing url. */
@@ -57,6 +54,7 @@
     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) {
@@ -64,12 +62,26 @@
                 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(
-                mDoc,
+                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
index ab8e85c..ec86d0f 100644
--- 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
@@ -22,7 +22,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
-import org.w3c.dom.Document;
 
 @RunWith(JUnit4.class)
 public class ThirdPartyVerificationTest {
@@ -34,15 +33,12 @@
     private static final String VALID_FILE_NAME = "valid.xml";
     private static final String MISSING_URL_FILE_NAME = "missing-url.xml";
 
-    private Document mDoc = null;
-
     /** 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.");
-        mDoc = TestUtils.document();
     }
 
     /** Test for valid. */
@@ -50,6 +46,7 @@
     public void testValid() throws Exception {
         System.out.println("starting testValid.");
         testHrToOdThirdPartyVerification(VALID_FILE_NAME);
+        testOdToHrThirdPartyVerification(VALID_FILE_NAME);
     }
 
     /** Tests missing url. */
@@ -57,6 +54,7 @@
     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) {
@@ -64,12 +62,26 @@
                 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(
-                mDoc,
+                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
index 56503f7..f494240 100644
--- 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
@@ -22,7 +22,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
-import org.w3c.dom.Document;
 
 @RunWith(JUnit4.class)
 public class TransparencyInfoTest {
@@ -35,12 +34,9 @@
     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";
 
-    private Document mDoc = null;
-
     @Before
     public void setUp() throws Exception {
         System.out.println("set up.");
-        mDoc = TestUtils.document();
     }
 
     /** Test for transparency info valid empty. */
@@ -48,6 +44,7 @@
     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. */
@@ -55,6 +52,7 @@
     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. */
@@ -62,14 +60,24 @@
     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(
-                mDoc,
+                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
index 6a29b86..ea90993 100644
--- 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
@@ -38,6 +38,7 @@
 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;
@@ -98,6 +99,19 @@
         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.
      */
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 0000000..1aa3aa9
--- /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/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 0000000..3fbe359
--- /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/systemappsafetylabel/od/missing-url.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/od/missing-url.xml
new file mode 100644
index 0000000..33b7965
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/od/missing-url.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/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 0000000..0b5a46f
--- /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/transparencyinfo/hr/with-developer-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-developer-info.xml
index 862bda4..d16caae 100644
--- 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
@@ -7,5 +7,5 @@
         countryRegion="US"
         relationship="aosp"
         website="example.com"
-        appDeveloperRegistryId="registry_id" />
+        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/with-developer-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-developer-info.xml
index 101c98b..d7a4e1a 100644
--- 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
@@ -7,5 +7,6 @@
         <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/general/hr.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml
index 36beb93..8f854ad 100644
--- 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
@@ -1,6 +1,4 @@
 <app-metadata-bundles version="123">
-    <system-app-safety-label url="www.example.com">
-    </system-app-safety-label>
     <safety-labels version="12345">
         <data-labels>
             <data-shared dataCategory="location"
@@ -21,6 +19,8 @@
         <third-party-verification url="www.example.com">
         </third-party-verification>
     </safety-labels>
+    <system-app-safety-label url="www.example.com">
+    </system-app-safety-label>
     <transparency-info>
         <developer-info
             name="max"
@@ -29,7 +29,7 @@
             countryRegion="US"
             relationship="aosp"
             website="example.com"
-            appDeveloperRegistryId="registry_id" />
+            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
index db21280..8f1dc64 100644
--- 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
@@ -42,6 +42,7 @@
             <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"/>