Merge "Fix tethering jarjar rule for LocalLog"
diff --git a/Android.bp b/Android.bp
index aeaaca3d..a93a155 100644
--- a/Android.bp
+++ b/Android.bp
@@ -371,7 +371,7 @@
 java_library {
     name: "framework-updatable-stubs-module_libs_api",
     static_libs: [
-        "framework-sdkextensions-stubs-module_libs_api",
+        "framework-sdkextensions.stubs.module_lib",
         "framework-tethering.stubs.module_lib",
         "updatable_media_stubs",
     ],
diff --git a/cmds/statsd/src/anomaly/AlarmTracker.cpp b/cmds/statsd/src/anomaly/AlarmTracker.cpp
index 019a9f7..a21327b 100644
--- a/cmds/statsd/src/anomaly/AlarmTracker.cpp
+++ b/cmds/statsd/src/anomaly/AlarmTracker.cpp
@@ -61,11 +61,11 @@
 }
 
 int64_t AlarmTracker::findNextAlarmSec(int64_t currentTimeSec) {
-    if (currentTimeSec <= mAlarmSec) {
+    if (currentTimeSec < mAlarmSec) {
         return mAlarmSec;
     }
     int64_t periodsForward =
-        ((currentTimeSec - mAlarmSec) * MS_PER_SEC - 1) / mAlarmConfig.period_millis() + 1;
+        ((currentTimeSec - mAlarmSec) * MS_PER_SEC) / mAlarmConfig.period_millis() + 1;
     return mAlarmSec + periodsForward * mAlarmConfig.period_millis() / MS_PER_SEC;
 }
 
diff --git a/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp b/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
index 5e6de1c..e664023 100644
--- a/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
@@ -40,23 +40,47 @@
     alarm.set_offset_millis(15 * MS_PER_SEC);
     alarm.set_period_millis(60 * 60 * MS_PER_SEC);  // 1hr
     int64_t startMillis = 100000000 * MS_PER_SEC;
+    int64_t nextAlarmTime = startMillis / MS_PER_SEC + 15;
     AlarmTracker tracker(startMillis, startMillis, alarm, kConfigKey, subscriberAlarmMonitor);
 
-    EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15));
+    EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
 
     uint64_t currentTimeSec = startMillis / MS_PER_SEC + 10;
     std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> firedAlarmSet =
         subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
     EXPECT_TRUE(firedAlarmSet.empty());
     tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
-    EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15));
+    EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
+    EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime);
 
     currentTimeSec = startMillis / MS_PER_SEC + 7000;
+    nextAlarmTime = startMillis / MS_PER_SEC + 15 + 2 * 60 * 60;
     firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
     EXPECT_EQ(firedAlarmSet.size(), 1u);
     tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
     EXPECT_TRUE(firedAlarmSet.empty());
-    EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15 + 2 * 60 * 60));
+    EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
+    EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime);
+
+    // Alarm fires exactly on time.
+    currentTimeSec = startMillis / MS_PER_SEC + 15 + 2 * 60 * 60;
+    nextAlarmTime = startMillis / MS_PER_SEC + 15 + 3 * 60 * 60;
+    firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
+    ASSERT_EQ(firedAlarmSet.size(), 1u);
+    tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
+    EXPECT_TRUE(firedAlarmSet.empty());
+    EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
+    EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime);
+
+    // Alarm fires exactly 1 period late.
+    currentTimeSec = startMillis / MS_PER_SEC + 15 + 4 * 60 * 60;
+    nextAlarmTime = startMillis / MS_PER_SEC + 15 + 5 * 60 * 60;
+    firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
+    ASSERT_EQ(firedAlarmSet.size(), 1u);
+    tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
+    EXPECT_TRUE(firedAlarmSet.empty());
+    EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
+    EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime);
 }
 
 }  // namespace statsd
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 647f630..febb293 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -35,7 +35,7 @@
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
 
-import libcore.timezone.ZoneInfoDb;
+import com.android.i18n.timezone.ZoneInfoDb;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index 8e8409d..e733938 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -18,8 +18,8 @@
 
 import android.util.TimeFormatException;
 
-import libcore.timezone.ZoneInfoDb;
-import libcore.util.ZoneInfo;
+import com.android.i18n.timezone.ZoneInfoData;
+import com.android.i18n.timezone.ZoneInfoDb;
 
 import java.util.Locale;
 import java.util.TimeZone;
@@ -1059,15 +1059,15 @@
      * to the enclosing object, but others do not: thus separate state is retained.
      */
     private static class TimeCalculator {
-        public final ZoneInfo.WallTime wallTime;
+        public final ZoneInfoData.WallTime wallTime;
         public String timezone;
 
         // Information about the current timezone.
-        private ZoneInfo zoneInfo;
+        private ZoneInfoData mZoneInfoData;
 
         public TimeCalculator(String timezoneId) {
-            this.zoneInfo = lookupZoneInfo(timezoneId);
-            this.wallTime = new ZoneInfo.WallTime();
+            this.mZoneInfoData = lookupZoneInfoData(timezoneId);
+            this.wallTime = new ZoneInfoData.WallTime();
         }
 
         public long toMillis(boolean ignoreDst) {
@@ -1075,7 +1075,7 @@
                 wallTime.setIsDst(-1);
             }
 
-            int r = wallTime.mktime(zoneInfo);
+            int r = wallTime.mktime(mZoneInfoData);
             if (r == -1) {
                 return -1;
             }
@@ -1087,7 +1087,7 @@
             int intSeconds = (int) (millis / 1000);
 
             updateZoneInfoFromTimeZone();
-            wallTime.localtime(intSeconds, zoneInfo);
+            wallTime.localtime(intSeconds, mZoneInfoData);
         }
 
         public String format(String format) {
@@ -1095,31 +1095,31 @@
                 format = "%c";
             }
             TimeFormatter formatter = new TimeFormatter();
-            return formatter.format(format, wallTime, zoneInfo);
+            return formatter.format(format, wallTime, mZoneInfoData);
         }
 
         private void updateZoneInfoFromTimeZone() {
-            if (!zoneInfo.getID().equals(timezone)) {
-                this.zoneInfo = lookupZoneInfo(timezone);
+            if (!mZoneInfoData.getID().equals(timezone)) {
+                this.mZoneInfoData = lookupZoneInfoData(timezone);
             }
         }
 
-        private static ZoneInfo lookupZoneInfo(String timezoneId) {
-            ZoneInfo zoneInfo = ZoneInfoDb.getInstance().makeTimeZone(timezoneId);
-            if (zoneInfo == null) {
-                zoneInfo = ZoneInfoDb.getInstance().makeTimeZone("GMT");
+        private static ZoneInfoData lookupZoneInfoData(String timezoneId) {
+            ZoneInfoData zoneInfoData = ZoneInfoDb.getInstance().makeZoneInfoData(timezoneId);
+            if (zoneInfoData == null) {
+                zoneInfoData = ZoneInfoDb.getInstance().makeZoneInfoData("GMT");
             }
-            if (zoneInfo == null) {
+            if (zoneInfoData == null) {
                 throw new AssertionError("GMT not found: \"" + timezoneId + "\"");
             }
-            return zoneInfo;
+            return zoneInfoData;
         }
 
         public void switchTimeZone(String timezone) {
-            int seconds = wallTime.mktime(zoneInfo);
+            int seconds = wallTime.mktime(mZoneInfoData);
             this.timezone = timezone;
             updateZoneInfoFromTimeZone();
-            wallTime.localtime(seconds, zoneInfo);
+            wallTime.localtime(seconds, mZoneInfoData);
         }
 
         public String format2445(boolean hasTime) {
diff --git a/core/java/android/text/format/TimeFormatter.java b/core/java/android/text/format/TimeFormatter.java
index f7fd89d..cd541f2 100644
--- a/core/java/android/text/format/TimeFormatter.java
+++ b/core/java/android/text/format/TimeFormatter.java
@@ -22,8 +22,9 @@
 
 import android.content.res.Resources;
 
+import com.android.i18n.timezone.ZoneInfoData;
+
 import libcore.icu.LocaleData;
-import libcore.util.ZoneInfo;
 
 import java.nio.CharBuffer;
 import java.time.Instant;
@@ -94,8 +95,8 @@
      * incorrect digit localization behavior.
      */
     String formatMillisWithFixedFormat(long timeMillis) {
-        // This method is deliberately not a general purpose replacement for
-        // format(String, ZoneInfo.WallTime, ZoneInfo): It hard-codes the pattern used; many of the
+        // This method is deliberately not a general purpose replacement for format(String,
+        // ZoneInfoData.WallTime, ZoneInfoData): It hard-codes the pattern used; many of the
         // pattern characters supported by Time.format() have unusual behavior which would make
         // using java.time.format or similar packages difficult. It would be a lot of work to share
         // behavior and many internal Android usecases can be covered by this common pattern
@@ -144,7 +145,8 @@
     /**
      * Format the specified {@code wallTime} using {@code pattern}. The output is returned.
      */
-    public String format(String pattern, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) {
+    public String format(String pattern, ZoneInfoData.WallTime wallTime,
+            ZoneInfoData zoneInfoData) {
         try {
             StringBuilder stringBuilder = new StringBuilder();
 
@@ -153,7 +155,7 @@
             // and locale sensitive strings are output directly using outputBuilder.
             numberFormatter = new Formatter(stringBuilder, Locale.US);
 
-            formatInternal(pattern, wallTime, zoneInfo);
+            formatInternal(pattern, wallTime, zoneInfoData);
             String result = stringBuilder.toString();
             // The localizeDigits() behavior is the source of a bug since some formats are defined
             // as being in ASCII and not localized.
@@ -186,13 +188,14 @@
      * Format the specified {@code wallTime} using {@code pattern}. The output is written to
      * {@link #outputBuilder}.
      */
-    private void formatInternal(String pattern, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) {
+    private void formatInternal(String pattern, ZoneInfoData.WallTime wallTime,
+            ZoneInfoData zoneInfoData) {
         CharBuffer formatBuffer = CharBuffer.wrap(pattern);
         while (formatBuffer.remaining() > 0) {
             boolean outputCurrentChar = true;
             char currentChar = formatBuffer.get(formatBuffer.position());
             if (currentChar == '%') {
-                outputCurrentChar = handleToken(formatBuffer, wallTime, zoneInfo);
+                outputCurrentChar = handleToken(formatBuffer, wallTime, zoneInfoData);
             }
             if (outputCurrentChar) {
                 outputBuilder.append(formatBuffer.get(formatBuffer.position()));
@@ -201,8 +204,8 @@
         }
     }
 
-    private boolean handleToken(CharBuffer formatBuffer, ZoneInfo.WallTime wallTime,
-            ZoneInfo zoneInfo) {
+    private boolean handleToken(CharBuffer formatBuffer, ZoneInfoData.WallTime wallTime,
+            ZoneInfoData zoneInfoData) {
 
         // The char at formatBuffer.position() is expected to be '%' at this point.
         int modifier = 0;
@@ -247,10 +250,10 @@
                     outputYear(wallTime.getYear(), true, false, modifier);
                     return false;
                 case 'c':
-                    formatInternal(dateTimeFormat, wallTime, zoneInfo);
+                    formatInternal(dateTimeFormat, wallTime, zoneInfoData);
                     return false;
                 case 'D':
-                    formatInternal("%m/%d/%y", wallTime, zoneInfo);
+                    formatInternal("%m/%d/%y", wallTime, zoneInfoData);
                     return false;
                 case 'd':
                     numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
@@ -272,7 +275,7 @@
                             wallTime.getMonthDay());
                     return false;
                 case 'F':
-                    formatInternal("%Y-%m-%d", wallTime, zoneInfo);
+                    formatInternal("%Y-%m-%d", wallTime, zoneInfoData);
                     return false;
                 case 'H':
                     numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
@@ -315,21 +318,21 @@
                             : localeData.amPm[0], FORCE_LOWER_CASE);
                     return false;
                 case 'R':
-                    formatInternal("%H:%M", wallTime, zoneInfo);
+                    formatInternal("%H:%M", wallTime, zoneInfoData);
                     return false;
                 case 'r':
-                    formatInternal("%I:%M:%S %p", wallTime, zoneInfo);
+                    formatInternal("%I:%M:%S %p", wallTime, zoneInfoData);
                     return false;
                 case 'S':
                     numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
                             wallTime.getSecond());
                     return false;
                 case 's':
-                    int timeInSeconds = wallTime.mktime(zoneInfo);
+                    int timeInSeconds = wallTime.mktime(zoneInfoData);
                     outputBuilder.append(Integer.toString(timeInSeconds));
                     return false;
                 case 'T':
-                    formatInternal("%H:%M:%S", wallTime, zoneInfo);
+                    formatInternal("%H:%M:%S", wallTime, zoneInfoData);
                     return false;
                 case 't':
                     outputBuilder.append('\t');
@@ -383,7 +386,7 @@
                     return false;
                 }
                 case 'v':
-                    formatInternal("%e-%b-%Y", wallTime, zoneInfo);
+                    formatInternal("%e-%b-%Y", wallTime, zoneInfoData);
                     return false;
                 case 'W':
                     int n = (wallTime.getYearDay() + DAYSPERWEEK - (
@@ -395,10 +398,10 @@
                     numberFormatter.format("%d", wallTime.getWeekDay());
                     return false;
                 case 'X':
-                    formatInternal(timeOnlyFormat, wallTime, zoneInfo);
+                    formatInternal(timeOnlyFormat, wallTime, zoneInfoData);
                     return false;
                 case 'x':
-                    formatInternal(dateOnlyFormat, wallTime, zoneInfo);
+                    formatInternal(dateOnlyFormat, wallTime, zoneInfoData);
                     return false;
                 case 'y':
                     outputYear(wallTime.getYear(), false, true, modifier);
@@ -411,7 +414,8 @@
                         return false;
                     }
                     boolean isDst = wallTime.getIsDst() != 0;
-                    modifyAndAppend(zoneInfo.getDisplayName(isDst, TimeZone.SHORT), modifier);
+                    modifyAndAppend(TimeZone.getTimeZone(zoneInfoData.getID())
+                            .getDisplayName(isDst, TimeZone.SHORT), modifier);
                     return false;
                 case 'z': {
                     if (wallTime.getIsDst() < 0) {
@@ -432,7 +436,7 @@
                     return false;
                 }
                 case '+':
-                    formatInternal("%a %b %e %H:%M:%S %Z %Y", wallTime, zoneInfo);
+                    formatInternal("%a %b %e %H:%M:%S %Z %Y", wallTime, zoneInfoData);
                     return false;
                 case '%':
                     // If conversion char is undefined, behavior is undefined. Print out the
diff --git a/core/java/android/timezone/TzDataSetVersion.java b/core/java/android/timezone/TzDataSetVersion.java
index f993012..e1fb932 100644
--- a/core/java/android/timezone/TzDataSetVersion.java
+++ b/core/java/android/timezone/TzDataSetVersion.java
@@ -50,14 +50,14 @@
      * Returns the major tz data format version supported by this device.
      */
     public static int currentFormatMajorVersion() {
-        return libcore.timezone.TzDataSetVersion.currentFormatMajorVersion();
+        return com.android.i18n.timezone.TzDataSetVersion.currentFormatMajorVersion();
     }
 
     /**
      * Returns the minor tz data format version supported by this device.
      */
     public static int currentFormatMinorVersion() {
-        return libcore.timezone.TzDataSetVersion.currentFormatMinorVersion();
+        return com.android.i18n.timezone.TzDataSetVersion.currentFormatMinorVersion();
     }
 
     /**
@@ -65,7 +65,7 @@
      * with the current system image, and set of active modules.
      */
     public static boolean isCompatibleWithThisDevice(TzDataSetVersion tzDataSetVersion) {
-        return libcore.timezone.TzDataSetVersion.isCompatibleWithThisDevice(
+        return com.android.i18n.timezone.TzDataSetVersion.isCompatibleWithThisDevice(
                 tzDataSetVersion.mDelegate);
     }
 
@@ -76,8 +76,8 @@
     public static TzDataSetVersion read() throws IOException, TzDataSetException {
         try {
             return new TzDataSetVersion(
-                    libcore.timezone.TzDataSetVersion.readTimeZoneModuleVersion());
-        } catch (libcore.timezone.TzDataSetVersion.TzDataSetException e) {
+                    com.android.i18n.timezone.TzDataSetVersion.readTimeZoneModuleVersion());
+        } catch (com.android.i18n.timezone.TzDataSetVersion.TzDataSetException e) {
             throw new TzDataSetException(e.getMessage(), e);
         }
     }
@@ -100,9 +100,9 @@
     }
 
     @NonNull
-    private final libcore.timezone.TzDataSetVersion mDelegate;
+    private final com.android.i18n.timezone.TzDataSetVersion mDelegate;
 
-    private TzDataSetVersion(@NonNull libcore.timezone.TzDataSetVersion delegate) {
+    private TzDataSetVersion(@NonNull com.android.i18n.timezone.TzDataSetVersion delegate) {
         mDelegate = Objects.requireNonNull(delegate);
     }
 
diff --git a/core/java/android/timezone/ZoneInfoDb.java b/core/java/android/timezone/ZoneInfoDb.java
index 9354a69..65d6ead 100644
--- a/core/java/android/timezone/ZoneInfoDb.java
+++ b/core/java/android/timezone/ZoneInfoDb.java
@@ -41,16 +41,16 @@
     public static ZoneInfoDb getInstance() {
         synchronized (sLock) {
             if (sInstance == null) {
-                sInstance = new ZoneInfoDb(libcore.timezone.ZoneInfoDb.getInstance());
+                sInstance = new ZoneInfoDb(com.android.i18n.timezone.ZoneInfoDb.getInstance());
             }
         }
         return sInstance;
     }
 
     @NonNull
-    private final libcore.timezone.ZoneInfoDb mDelegate;
+    private final com.android.i18n.timezone.ZoneInfoDb mDelegate;
 
-    private ZoneInfoDb(libcore.timezone.ZoneInfoDb delegate) {
+    private ZoneInfoDb(com.android.i18n.timezone.ZoneInfoDb delegate) {
         mDelegate = Objects.requireNonNull(delegate);
     }
 
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 6e41fc8..b2766a4 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -23,10 +23,11 @@
 import android.os.Build;
 import android.os.SystemClock;
 
+import com.android.i18n.timezone.ZoneInfoDb;
+
 import libcore.timezone.CountryTimeZones;
 import libcore.timezone.CountryTimeZones.TimeZoneMapping;
 import libcore.timezone.TimeZoneFinder;
-import libcore.timezone.ZoneInfoDb;
 
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index 4116afc..f89ee24 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -27,7 +27,8 @@
         "androidx.annotation_annotation",
         "netd_aidl_interface-unstable-java",
         "netlink-client",
-        "networkstack-aidl-interfaces-java",
+        // TODO: use networkstack-client instead of just including the AIDL interface
+        "networkstack-aidl-interfaces-unstable-java",
         "android.hardware.tetheroffload.config-V1.0-java",
         "android.hardware.tetheroffload.control-V1.0-java",
         "net-utils-framework-common",
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java
index 593d04a..a0198cc 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java
@@ -273,8 +273,9 @@
                 mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
                 0 /* requestCode */,
                 new Intent(Settings.ACTION_TETHER_SETTINGS)
-                        .setPackage(getSettingsPackageName(mContext.getPackageManager())),
-                Intent.FLAG_ACTIVITY_NEW_TASK | PendingIntent.FLAG_IMMUTABLE,
+                        .setPackage(getSettingsPackageName(mContext.getPackageManager()))
+                        .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
+                PendingIntent.FLAG_IMMUTABLE,
                 null /* options */);
 
         showNotification(R.drawable.stat_sys_tether_general, title, message,
@@ -317,8 +318,9 @@
                 mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
                 0 /* requestCode */,
                 new Intent(Settings.ACTION_TETHER_SETTINGS)
-                        .setPackage(getSettingsPackageName(mContext.getPackageManager())),
-                Intent.FLAG_ACTIVITY_NEW_TASK | PendingIntent.FLAG_IMMUTABLE,
+                        .setPackage(getSettingsPackageName(mContext.getPackageManager()))
+                        .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
+                PendingIntent.FLAG_IMMUTABLE,
                 null /* options */);
 
         showNotification(R.drawable.stat_sys_tether_general, title, message,
diff --git a/services/backup/OWNERS b/services/backup/OWNERS
index 9c21e8f..ba61d1c0 100644
--- a/services/backup/OWNERS
+++ b/services/backup/OWNERS
@@ -1,9 +1,7 @@
+# Bug component: 656484
+
 alsutton@google.com
-anniemeng@google.com
-brufino@google.com
 bryanmawhinney@google.com
-ctate@google.com
-jorlow@google.com
 nathch@google.com
 rthakohov@google.com
-
+tobiast@google.com
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 4c8fe4c..e1bcb0c 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5141,14 +5141,6 @@
         }
     }
 
-    private void onPackageAdded(String packageName, int uid) {
-        if (TextUtils.isEmpty(packageName) || uid < 0) {
-            Slog.wtf(TAG, "Invalid package in onPackageAdded: " + packageName + " | " + uid);
-            return;
-        }
-        mPermissionMonitor.onPackageAdded(packageName, uid);
-    }
-
     private void onPackageReplaced(String packageName, int uid) {
         if (TextUtils.isEmpty(packageName) || uid < 0) {
             Slog.wtf(TAG, "Invalid package in onPackageReplaced: " + packageName + " | " + uid);
@@ -5174,7 +5166,6 @@
             Slog.wtf(TAG, "Invalid package in onPackageRemoved: " + packageName + " | " + uid);
             return;
         }
-        mPermissionMonitor.onPackageRemoved(uid);
 
         final int userId = UserHandle.getUserId(uid);
         synchronized (mVpns) {
@@ -5224,8 +5215,6 @@
                 onUserRemoved(userId);
             } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
                 onUserUnlocked(userId);
-            } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
-                onPackageAdded(packageName, uid);
             } else if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
                 onPackageReplaced(packageName, uid);
             } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
diff --git a/services/core/java/com/android/server/RuntimeService.java b/services/core/java/com/android/server/RuntimeService.java
index bb39ccc..f4249f8 100644
--- a/services/core/java/com/android/server/RuntimeService.java
+++ b/services/core/java/com/android/server/RuntimeService.java
@@ -23,10 +23,9 @@
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
-import libcore.timezone.TimeZoneDataFiles;
-import libcore.util.CoreLibraryDebug;
-import libcore.util.DebugInfo;
-
+import com.android.i18n.timezone.DebugInfo;
+import com.android.i18n.timezone.I18nModuleDebug;
+import com.android.i18n.timezone.TimeZoneDataFiles;
 import com.android.internal.util.DumpUtils;
 import com.android.timezone.distro.DistroException;
 import com.android.timezone.distro.DistroVersion;
@@ -61,14 +60,14 @@
         boolean protoFormat = hasOption(args, "--proto");
         ProtoOutputStream proto = null;
 
-        DebugInfo coreLibraryDebugInfo = CoreLibraryDebug.getDebugInfo();
-        addTimeZoneApkDebugInfo(coreLibraryDebugInfo);
+        DebugInfo i18nLibraryDebugInfo = I18nModuleDebug.getDebugInfo();
+        addTimeZoneApkDebugInfo(i18nLibraryDebugInfo);
 
         if (protoFormat) {
             proto = new ProtoOutputStream(fd);
-            reportTimeZoneInfoProto(coreLibraryDebugInfo, proto);
+            reportTimeZoneInfoProto(i18nLibraryDebugInfo, proto);
         } else {
-            reportTimeZoneInfo(coreLibraryDebugInfo, pw);
+            reportTimeZoneInfo(i18nLibraryDebugInfo, pw);
         }
 
         if (protoFormat) {
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index f0b7150..c5aa8d5 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -72,7 +72,7 @@
  *
  * @hide
  */
-public class PermissionMonitor {
+public class PermissionMonitor implements PackageManagerInternal.PackageListObserver {
     private static final String TAG = "PermissionMonitor";
     private static final boolean DBG = true;
     protected static final Boolean SYSTEM = Boolean.TRUE;
@@ -102,44 +102,6 @@
     @GuardedBy("this")
     private final Set<Integer> mAllApps = new HashSet<>();
 
-    private class PackageListObserver implements PackageManagerInternal.PackageListObserver {
-
-        private int getPermissionForUid(int uid) {
-            int permission = 0;
-            // Check all the packages for this UID. The UID has the permission if any of the
-            // packages in it has the permission.
-            String[] packages = mPackageManager.getPackagesForUid(uid);
-            if (packages != null && packages.length > 0) {
-                for (String name : packages) {
-                    final PackageInfo app = getPackageInfo(name);
-                    if (app != null && app.requestedPermissions != null) {
-                        permission |= getNetdPermissionMask(app.requestedPermissions,
-                              app.requestedPermissionsFlags);
-                    }
-                }
-            } else {
-                // The last package of this uid is removed from device. Clean the package up.
-                permission = INetd.PERMISSION_UNINSTALLED;
-            }
-            return permission;
-        }
-
-        @Override
-        public void onPackageAdded(String packageName, int uid) {
-            sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
-        }
-
-        @Override
-        public void onPackageChanged(@NonNull String packageName, int uid) {
-            sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
-        }
-
-        @Override
-        public void onPackageRemoved(String packageName, int uid) {
-            sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
-        }
-    }
-
     public PermissionMonitor(Context context, INetd netd) {
         mPackageManager = context.getPackageManager();
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
@@ -153,7 +115,7 @@
 
         PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
         if (pmi != null) {
-            pmi.getPackageList(new PackageListObserver());
+            pmi.getPackageList(this);
         } else {
             loge("failed to get the PackageManagerInternal service");
         }
@@ -363,15 +325,38 @@
         return currentPermission;
     }
 
+    private int getPermissionForUid(final int uid) {
+        int permission = INetd.PERMISSION_NONE;
+        // Check all the packages for this UID. The UID has the permission if any of the
+        // packages in it has the permission.
+        final String[] packages = mPackageManager.getPackagesForUid(uid);
+        if (packages != null && packages.length > 0) {
+            for (String name : packages) {
+                final PackageInfo app = getPackageInfo(name);
+                if (app != null && app.requestedPermissions != null) {
+                    permission |= getNetdPermissionMask(app.requestedPermissions,
+                            app.requestedPermissionsFlags);
+                }
+            }
+        } else {
+            // The last package of this uid is removed from device. Clean the package up.
+            permission = INetd.PERMISSION_UNINSTALLED;
+        }
+        return permission;
+    }
+
     /**
-     * Called when a package is added. See {link #ACTION_PACKAGE_ADDED}.
+     * Called when a package is added.
      *
      * @param packageName The name of the new package.
      * @param uid The uid of the new package.
      *
      * @hide
      */
-    public synchronized void onPackageAdded(String packageName, int uid) {
+    @Override
+    public synchronized void onPackageAdded(@NonNull final String packageName, final int uid) {
+        sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
+
         // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
         // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
         final Boolean permission = highestPermissionForUid(mApps.get(uid), packageName);
@@ -398,13 +383,17 @@
     }
 
     /**
-     * Called when a package is removed. See {link #ACTION_PACKAGE_REMOVED}.
+     * Called when a package is removed.
      *
+     * @param packageName The name of the removed package or null.
      * @param uid containing the integer uid previously assigned to the package.
      *
      * @hide
      */
-    public synchronized void onPackageRemoved(int uid) {
+    @Override
+    public synchronized void onPackageRemoved(@NonNull final String packageName, final int uid) {
+        sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
+
         // If the newly-removed package falls within some VPN's uid range, update Netd with it.
         // This needs to happen before the mApps update below, since removeBypassingUids() depends
         // on mApps to check if the package can bypass VPN.
@@ -449,6 +438,19 @@
         }
     }
 
+    /**
+     * Called when a package is changed.
+     *
+     * @param packageName The name of the changed package.
+     * @param uid The uid of the changed package.
+     *
+     * @hide
+     */
+    @Override
+    public synchronized void onPackageChanged(@NonNull final String packageName, final int uid) {
+        sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
+    }
+
     private static int getNetdPermissionMask(String[] requestedPermissions,
                                              int[] requestedPermissionsFlags) {
         int permissions = 0;
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index 6fdde7a..fe6aad7 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -10,8 +10,8 @@
 toddke@google.com
 
 # apex support
-per-file ApexManager.java = dariofreni@google.com
-per-file StagingManager.java = dariofreni@google.com
+per-file ApexManager.java = dariofreni@google.com, ioffe@google.com, olilan@google.com
+per-file StagingManager.java = dariofreni@google.com, ioffe@google.com, olilan@google.com
 
 # dex
 per-file AbstractStatsBase.java = agampe@google.com, calin@google.com, ngeoffray@google.com
diff --git a/services/core/java/com/android/server/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java
index bbd1ae6..d4a71ed 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerService.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerService.java
@@ -37,6 +37,9 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
+import com.android.i18n.timezone.TimeZoneDataFiles;
+import com.android.i18n.timezone.TzDataSetVersion;
+import com.android.i18n.timezone.ZoneInfoDb;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.EventLogTags;
 import com.android.server.SystemService;
@@ -46,10 +49,7 @@
 import com.android.timezone.distro.TimeZoneDistro;
 import com.android.timezone.distro.installer.TimeZoneDistroInstaller;
 
-import libcore.timezone.TimeZoneDataFiles;
 import libcore.timezone.TimeZoneFinder;
-import libcore.timezone.TzDataSetVersion;
-import libcore.timezone.ZoneInfoDb;
 
 import java.io.File;
 import java.io.FileDescriptor;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 23b1512..c48ee11 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -74,6 +74,7 @@
 import android.view.contentcapture.ContentCaptureManager;
 import android.view.inputmethod.InputMethodSystemProperty;
 
+import com.android.i18n.timezone.ZoneInfoDb;
 import com.android.internal.R;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.notification.SystemNotificationChannels;
@@ -165,8 +166,6 @@
 import com.android.server.wm.WindowManagerGlobalLock;
 import com.android.server.wm.WindowManagerService;
 
-import libcore.timezone.ZoneInfoDb;
-
 import dalvik.system.VMRuntime;
 
 import java.io.File;
diff --git a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
index 5c6fe0f..2c4c4d0 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
@@ -43,13 +43,13 @@
 import android.app.timezone.RulesState;
 import android.os.ParcelFileDescriptor;
 
+import com.android.i18n.timezone.TzDataSetVersion;
 import com.android.timezone.distro.DistroVersion;
 import com.android.timezone.distro.StagedDistroOperation;
 import com.android.timezone.distro.TimeZoneDistro;
 import com.android.timezone.distro.installer.TimeZoneDistroInstaller;
 
 import libcore.io.IoUtils;
-import libcore.timezone.TzDataSetVersion;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index 1a049e6..d692825 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -542,13 +542,16 @@
 
         // Assign permission to special system apps
         assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
-                PHONE_PACKAGE_NAME);
+                PHONE_PACKAGE_NAME, true);
         assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
-                BLUETOOTH_PACKAGE_NAME);
+                BLUETOOTH_PACKAGE_NAME, true);
         assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
-                MMS_SERVICE_PACKAGE_NAME);
+                MMS_SERVICE_PACKAGE_NAME, true);
         assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
-                TELEPHONY_PROVIDER_PACKAGE_NAME);
+                TELEPHONY_PROVIDER_PACKAGE_NAME, true);
+        // CellbroadcastReceiver is a mainline module thus skip signature match.
+        assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
+                CellBroadcastUtils.getDefaultCellBroadcastReceiverPackageName(context), false);
 
         // Give AppOps permission to UID 1001 which contains multiple
         // apps, all of them should be able to write to telephony provider.
@@ -738,17 +741,23 @@
      * @param packageManager The package manager instance
      * @param appOps The AppOps manager instance
      * @param packageName The package name of the system app
+     * @param sigatureMatch whether to check signature match
      */
     private static void assignExclusiveSmsPermissionsToSystemApp(Context context,
-            PackageManager packageManager, AppOpsManager appOps, String packageName) {
+            PackageManager packageManager, AppOpsManager appOps, String packageName,
+            boolean sigatureMatch) {
         // First check package signature matches the caller's package signature.
         // Since this class is only used internally by the system, this check makes sure
         // the package signature matches system signature.
-        final int result = packageManager.checkSignatures(context.getPackageName(), packageName);
-        if (result != PackageManager.SIGNATURE_MATCH) {
-            Log.e(LOG_TAG, packageName + " does not have system signature");
-            return;
+        if (sigatureMatch) {
+            final int result = packageManager.checkSignatures(context.getPackageName(),
+                    packageName);
+            if (result != PackageManager.SIGNATURE_MATCH) {
+                Log.e(LOG_TAG, packageName + " does not have system signature");
+                return;
+            }
         }
+
         try {
             PackageInfo info = packageManager.getPackageInfo(packageName, 0);
             int mode = appOps.unsafeCheckOp(AppOpsManager.OPSTR_WRITE_SMS, info.applicationInfo.uid,
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 6b498b5..6897706 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -12608,7 +12608,6 @@
             @Nullable String mvnoMatchData) {
         try {
             if (!mccmnc.equals(getSimOperator())) {
-                Log.d(TAG, "The mccmnc does not match");
                 return false;
             }
             ITelephony service = getITelephony();
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index 7069e0a..2cdf70e 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -29,6 +29,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.util.RemoteCallbackListExt;
+import com.android.internal.util.ArrayUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -105,6 +106,11 @@
     // Locked on mLock, create unspecified disconnect cause.
     private ImsReasonInfo mLastDisconnectCause = new ImsReasonInfo();
 
+    // We hold onto the uris each time they change so that we can send it to a callback when its
+    // first added.
+    private Uri[] mUris = new Uri[0];
+    private boolean mUrisSet = false;
+
     /**
      * @hide
      */
@@ -208,19 +214,27 @@
     }
 
     /**
-     * The this device's subscriber associated {@link Uri}s have changed, which are used to filter
-     * out this device's {@link Uri}s during conference calling.
-     * @param uris
+     * Invoked when the {@link Uri}s associated to this device's subscriber have changed.
+     * These {@link Uri}s' are filtered out during conference calls.
+     *
+     * The {@link Uri}s are not guaranteed to be different between subsequent calls.
+     * @param uris changed uris
      */
     public final void onSubscriberAssociatedUriChanged(Uri[] uris) {
-        mCallbacks.broadcastAction((c) -> {
-            try {
-                c.onSubscriberAssociatedUriChanged(uris);
-            } catch (RemoteException e) {
-                Log.w(LOG_TAG, e + " " + "onSubscriberAssociatedUriChanged() - Skipping " +
-                        "callback.");
-            }
-        });
+        synchronized (mLock) {
+            mUris = ArrayUtils.cloneOrNull(uris);
+            mUrisSet = true;
+        }
+        mCallbacks.broadcastAction((c) -> onSubscriberAssociatedUriChanged(c, uris));
+    }
+
+    private void onSubscriberAssociatedUriChanged(IImsRegistrationCallback callback, Uri[] uris) {
+        try {
+            callback.onSubscriberAssociatedUriChanged(uris);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, e + " " + "onSubscriberAssociatedUriChanged() - Skipping "
+                    + "callback.");
+        }
     }
 
     private void updateToState(@ImsRegistrationTech int connType, int newState) {
@@ -233,6 +247,10 @@
 
     private void updateToDisconnectedState(ImsReasonInfo info) {
         synchronized (mLock) {
+            //We don't want to send this info over if we are disconnected
+            mUrisSet = false;
+            mUris = null;
+
             updateToState(REGISTRATION_TECH_NONE,
                     RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED);
             if (info != null) {
@@ -260,12 +278,17 @@
      * @param c the newly registered callback that will be updated with the current registration
      *         state.
      */
-    private void updateNewCallbackWithState(IImsRegistrationCallback c) throws RemoteException {
+    private void updateNewCallbackWithState(IImsRegistrationCallback c)
+            throws RemoteException {
         int state;
         ImsReasonInfo disconnectInfo;
+        boolean urisSet;
+        Uri[] uris;
         synchronized (mLock) {
             state = mRegistrationState;
             disconnectInfo = mLastDisconnectCause;
+            urisSet = mUrisSet;
+            uris = mUris;
         }
         switch (state) {
             case RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED: {
@@ -285,5 +308,8 @@
                 break;
             }
         }
+        if (urisSet) {
+            onSubscriberAssociatedUriChanged(c, uris);
+        }
     }
 }
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 76e3e2f..5eea0e8 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -76,7 +76,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
@@ -88,7 +87,6 @@
 import java.util.HashSet;
 import java.util.Set;
 
-
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class PermissionMonitorTest {
@@ -117,7 +115,6 @@
     @Mock private PackageManagerInternal mMockPmi;
     @Mock private UserManager mUserManager;
 
-    private PackageManagerInternal.PackageListObserver mObserver;
     private PermissionMonitor mPermissionMonitor;
 
     @Before
@@ -139,11 +136,7 @@
                   /* observer */ null));
         when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null);
         mPermissionMonitor.startMonitoring();
-
-        final ArgumentCaptor<PackageManagerInternal.PackageListObserver> observerCaptor =
-                ArgumentCaptor.forClass(PackageManagerInternal.PackageListObserver.class);
-        verify(mMockPmi).getPackageList(observerCaptor.capture());
-        mObserver = observerCaptor.getValue();
+        verify(mMockPmi).getPackageList(mPermissionMonitor);
     }
 
     private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
@@ -450,13 +443,13 @@
                 new int[]{MOCK_UID1});
 
         // Remove MOCK_UID1, expect no permission left for all user.
-        mPermissionMonitor.onPackageRemoved(MOCK_UID1);
-        removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_UID1);
+        mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
+        removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
         mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, new int[]{MOCK_UID1});
 
         // Remove SYSTEM_PACKAGE1, expect permission downgrade.
         when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{SYSTEM_PACKAGE2});
-        removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, SYSTEM_UID);
+        removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, SYSTEM_PACKAGE1, SYSTEM_UID);
         mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2},
                 new int[]{SYSTEM_UID});
 
@@ -465,7 +458,7 @@
 
         // Remove all packages, expect no permission left.
         when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{});
-        removePackageForUsers(new int[]{MOCK_USER2}, SYSTEM_UID);
+        removePackageForUsers(new int[]{MOCK_USER2}, SYSTEM_PACKAGE2, SYSTEM_UID);
         mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2},
                 new int[]{SYSTEM_UID, MOCK_UID1});
 
@@ -501,7 +494,8 @@
         reset(mNetdService);
 
         // When MOCK_UID1 package is uninstalled and reinstalled, expect Netd to be updated
-        mPermissionMonitor.onPackageRemoved(UserHandle.getUid(MOCK_USER1, MOCK_UID1));
+        mPermissionMonitor.onPackageRemoved(
+                MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1));
         verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
         mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1));
         verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
@@ -545,7 +539,8 @@
                 aryEq(new int[] {MOCK_UID1}));
 
         // Removed package should have its uid rules removed
-        mPermissionMonitor.onPackageRemoved(UserHandle.getUid(MOCK_USER1, MOCK_UID1));
+        mPermissionMonitor.onPackageRemoved(
+                MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1));
         verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
     }
 
@@ -559,9 +554,9 @@
         }
     }
 
-    private void removePackageForUsers(int[] users, int uid) {
+    private void removePackageForUsers(int[] users, String packageName, int uid) {
         for (final int user : users) {
-            mPermissionMonitor.onPackageRemoved(UserHandle.getUid(user, uid));
+            mPermissionMonitor.onPackageRemoved(packageName, UserHandle.getUid(user, uid));
         }
     }
 
@@ -647,7 +642,7 @@
     private PackageInfo addPackage(String packageName, int uid, String[] permissions)
             throws Exception {
         PackageInfo packageInfo = setPackagePermissions(packageName, uid, permissions);
-        mObserver.onPackageAdded(packageName, uid);
+        mPermissionMonitor.onPackageAdded(packageName, uid);
         return packageInfo;
     }
 
@@ -678,7 +673,7 @@
         when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
         when(mPackageManager.getPackagesForUid(MOCK_UID1))
               .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
-        mObserver.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1);
+        mPermissionMonitor.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1);
         mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
                 | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
     }
@@ -692,7 +687,7 @@
                 | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
 
         when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
-        mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
+        mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
         mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
     }
 
@@ -705,7 +700,7 @@
                 | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
 
         when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
-        mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
+        mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
         mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
 
         addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
@@ -719,10 +714,7 @@
         addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {});
         mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID1});
 
-        // When updating a package, the broadcast receiver gets two broadcasts (a remove and then an
-        // add), but the observer sees only one callback (an update).
-        setPackagePermissions(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
-        mObserver.onPackageChanged(MOCK_PACKAGE1, MOCK_UID1);
+        addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
         mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
     }
 
@@ -740,7 +732,7 @@
         when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{
                 MOCK_PACKAGE2});
 
-        mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
+        mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
         mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
     }