Merge "Add getNetworkSpecifier() and getCarrierConfig()"
diff --git a/api/current.txt b/api/current.txt
index 2dc6430..964712a3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8226,6 +8226,7 @@
     field public static final java.lang.String USER_SERVICE = "user";
     field public static final java.lang.String VIBRATOR_SERVICE = "vibrator";
     field public static final java.lang.String WALLPAPER_SERVICE = "wallpaper";
+    field public static final java.lang.String WIFI_AWARE_SERVICE = "wifiaware";
     field public static final java.lang.String WIFI_P2P_SERVICE = "wifip2p";
     field public static final java.lang.String WIFI_SERVICE = "wifi";
     field public static final java.lang.String WINDOW_SERVICE = "window";
@@ -9886,6 +9887,7 @@
     field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
     field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
     field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
+    field public static final java.lang.String FEATURE_WIFI_AWARE = "android.hardware.wifi.aware";
     field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
     field public static final int GET_ACTIVITIES = 1; // 0x1
     field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
@@ -23771,6 +23773,7 @@
     field public static final int TRANSPORT_ETHERNET = 3; // 0x3
     field public static final int TRANSPORT_VPN = 4; // 0x4
     field public static final int TRANSPORT_WIFI = 1; // 0x1
+    field public static final int TRANSPORT_WIFI_AWARE = 5; // 0x5
   }
 
   public class NetworkInfo implements android.os.Parcelable {
@@ -24777,6 +24780,122 @@
 
 }
 
+package android.net.wifi.aware {
+
+  public class AttachCallback {
+    ctor public AttachCallback();
+    method public void onAttachFailed();
+    method public void onAttached(android.net.wifi.aware.WifiAwareSession);
+  }
+
+  public final class Characteristics implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getMaxMatchFilterLength();
+    method public int getMaxServiceNameLength();
+    method public int getMaxServiceSpecificInfoLength();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.aware.Characteristics> CREATOR;
+  }
+
+  public class DiscoverySession {
+    method public java.lang.String createNetworkSpecifier(android.net.wifi.aware.PeerHandle, byte[]);
+    method public void destroy();
+    method public static int getMaxSendRetryCount();
+    method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[], int);
+    method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
+  }
+
+  public class DiscoverySessionCallback {
+    ctor public DiscoverySessionCallback();
+    method public void onMessageReceived(android.net.wifi.aware.PeerHandle, byte[]);
+    method public void onMessageSendFailed(int);
+    method public void onMessageSendSucceeded(int);
+    method public void onPublishStarted(android.net.wifi.aware.PublishDiscoverySession);
+    method public void onServiceDiscovered(android.net.wifi.aware.PeerHandle, byte[], java.util.List<byte[]>);
+    method public void onSessionConfigFailed();
+    method public void onSessionConfigUpdated();
+    method public void onSessionTerminated();
+    method public void onSubscribeStarted(android.net.wifi.aware.SubscribeDiscoverySession);
+  }
+
+  public class IdentityChangedListener {
+    ctor public IdentityChangedListener();
+    method public void onIdentityChanged(byte[]);
+  }
+
+  public class PeerHandle {
+  }
+
+  public final class PublishConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.aware.PublishConfig> CREATOR;
+    field public static final int PUBLISH_TYPE_SOLICITED = 1; // 0x1
+    field public static final int PUBLISH_TYPE_UNSOLICITED = 0; // 0x0
+  }
+
+  public static final class PublishConfig.Builder {
+    ctor public PublishConfig.Builder();
+    method public android.net.wifi.aware.PublishConfig build();
+    method public android.net.wifi.aware.PublishConfig.Builder setMatchFilter(java.util.List<byte[]>);
+    method public android.net.wifi.aware.PublishConfig.Builder setPublishCount(int);
+    method public android.net.wifi.aware.PublishConfig.Builder setPublishType(int);
+    method public android.net.wifi.aware.PublishConfig.Builder setServiceName(java.lang.String);
+    method public android.net.wifi.aware.PublishConfig.Builder setServiceSpecificInfo(byte[]);
+    method public android.net.wifi.aware.PublishConfig.Builder setTerminateNotificationEnabled(boolean);
+    method public android.net.wifi.aware.PublishConfig.Builder setTtlSec(int);
+  }
+
+  public class PublishDiscoverySession extends android.net.wifi.aware.DiscoverySession {
+    method public void updatePublish(android.net.wifi.aware.PublishConfig);
+  }
+
+  public final class SubscribeConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.aware.SubscribeConfig> CREATOR;
+    field public static final int MATCH_STYLE_ALL = 1; // 0x1
+    field public static final int MATCH_STYLE_FIRST_ONLY = 0; // 0x0
+    field public static final int SUBSCRIBE_TYPE_ACTIVE = 1; // 0x1
+    field public static final int SUBSCRIBE_TYPE_PASSIVE = 0; // 0x0
+  }
+
+  public static final class SubscribeConfig.Builder {
+    ctor public SubscribeConfig.Builder();
+    method public android.net.wifi.aware.SubscribeConfig build();
+    method public android.net.wifi.aware.SubscribeConfig.Builder setMatchFilter(java.util.List<byte[]>);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setMatchStyle(int);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setServiceName(java.lang.String);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setServiceSpecificInfo(byte[]);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setSubscribeCount(int);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setSubscribeType(int);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setTerminateNotificationEnabled(boolean);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setTtlSec(int);
+  }
+
+  public class SubscribeDiscoverySession extends android.net.wifi.aware.DiscoverySession {
+    method public void updateSubscribe(android.net.wifi.aware.SubscribeConfig);
+  }
+
+  public class WifiAwareManager {
+    method public void attach(android.net.wifi.aware.AttachCallback, android.os.Handler);
+    method public void attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler);
+    method public android.net.wifi.aware.Characteristics getCharacteristics();
+    method public boolean isAvailable();
+    field public static final java.lang.String ACTION_WIFI_AWARE_STATE_CHANGED = "android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED";
+    field public static final int WIFI_AWARE_DATA_PATH_ROLE_INITIATOR = 0; // 0x0
+    field public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1; // 0x1
+  }
+
+  public class WifiAwareSession {
+    method public java.lang.String createNetworkSpecifier(int, byte[], byte[]);
+    method public void destroy();
+    method public void publish(android.net.wifi.aware.PublishConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler);
+    method public void subscribe(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler);
+  }
+
+}
+
 package android.net.wifi.p2p {
 
   public class WifiP2pConfig implements android.os.Parcelable {
@@ -54803,8 +54922,10 @@
   public final class FileTime implements java.lang.Comparable {
     method public int compareTo(java.nio.file.attribute.FileTime);
     method public static java.nio.file.attribute.FileTime from(long, java.util.concurrent.TimeUnit);
+    method public static java.nio.file.attribute.FileTime from(java.time.Instant);
     method public static java.nio.file.attribute.FileTime fromMillis(long);
     method public long to(java.util.concurrent.TimeUnit);
+    method public java.time.Instant toInstant();
     method public long toMillis();
   }
 
@@ -58334,6 +58455,1515 @@
 
 }
 
+package java.time {
+
+  public abstract class Clock {
+    ctor protected Clock();
+    method public static java.time.Clock fixed(java.time.Instant, java.time.ZoneId);
+    method public abstract java.time.ZoneId getZone();
+    method public abstract java.time.Instant instant();
+    method public long millis();
+    method public static java.time.Clock offset(java.time.Clock, java.time.Duration);
+    method public static java.time.Clock system(java.time.ZoneId);
+    method public static java.time.Clock systemDefaultZone();
+    method public static java.time.Clock systemUTC();
+    method public static java.time.Clock tick(java.time.Clock, java.time.Duration);
+    method public static java.time.Clock tickMinutes(java.time.ZoneId);
+    method public static java.time.Clock tickSeconds(java.time.ZoneId);
+    method public abstract java.time.Clock withZone(java.time.ZoneId);
+  }
+
+  public class DateTimeException extends java.lang.RuntimeException {
+    ctor public DateTimeException(java.lang.String);
+    ctor public DateTimeException(java.lang.String, java.lang.Throwable);
+  }
+
+  public final class DayOfWeek extends java.lang.Enum implements java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public static java.time.DayOfWeek from(java.time.temporal.TemporalAccessor);
+    method public int get(java.time.temporal.TemporalField);
+    method public java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getValue();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public java.time.DayOfWeek minus(long);
+    method public static java.time.DayOfWeek of(int);
+    method public java.time.DayOfWeek plus(long);
+    method public <R> R query(java.time.temporal.TemporalQuery<R>);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public static java.time.DayOfWeek valueOf(java.lang.String);
+    method public static final java.time.DayOfWeek[] values();
+    enum_constant public static final java.time.DayOfWeek FRIDAY;
+    enum_constant public static final java.time.DayOfWeek MONDAY;
+    enum_constant public static final java.time.DayOfWeek SATURDAY;
+    enum_constant public static final java.time.DayOfWeek SUNDAY;
+    enum_constant public static final java.time.DayOfWeek THURSDAY;
+    enum_constant public static final java.time.DayOfWeek TUESDAY;
+    enum_constant public static final java.time.DayOfWeek WEDNESDAY;
+  }
+
+  public final class Duration implements java.lang.Comparable java.io.Serializable java.time.temporal.TemporalAmount {
+    method public java.time.Duration abs();
+    method public java.time.temporal.Temporal addTo(java.time.temporal.Temporal);
+    method public static java.time.Duration between(java.time.temporal.Temporal, java.time.temporal.Temporal);
+    method public int compareTo(java.time.Duration);
+    method public java.time.Duration dividedBy(long);
+    method public static java.time.Duration from(java.time.temporal.TemporalAmount);
+    method public long get(java.time.temporal.TemporalUnit);
+    method public int getNano();
+    method public long getSeconds();
+    method public java.util.List<java.time.temporal.TemporalUnit> getUnits();
+    method public boolean isNegative();
+    method public boolean isZero();
+    method public java.time.Duration minus(java.time.Duration);
+    method public java.time.Duration minus(long, java.time.temporal.TemporalUnit);
+    method public java.time.Duration minusDays(long);
+    method public java.time.Duration minusHours(long);
+    method public java.time.Duration minusMillis(long);
+    method public java.time.Duration minusMinutes(long);
+    method public java.time.Duration minusNanos(long);
+    method public java.time.Duration minusSeconds(long);
+    method public java.time.Duration multipliedBy(long);
+    method public java.time.Duration negated();
+    method public static java.time.Duration of(long, java.time.temporal.TemporalUnit);
+    method public static java.time.Duration ofDays(long);
+    method public static java.time.Duration ofHours(long);
+    method public static java.time.Duration ofMillis(long);
+    method public static java.time.Duration ofMinutes(long);
+    method public static java.time.Duration ofNanos(long);
+    method public static java.time.Duration ofSeconds(long);
+    method public static java.time.Duration ofSeconds(long, long);
+    method public static java.time.Duration parse(java.lang.CharSequence);
+    method public java.time.Duration plus(java.time.Duration);
+    method public java.time.Duration plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.Duration plusDays(long);
+    method public java.time.Duration plusHours(long);
+    method public java.time.Duration plusMillis(long);
+    method public java.time.Duration plusMinutes(long);
+    method public java.time.Duration plusNanos(long);
+    method public java.time.Duration plusSeconds(long);
+    method public java.time.temporal.Temporal subtractFrom(java.time.temporal.Temporal);
+    method public long toDays();
+    method public long toHours();
+    method public long toMillis();
+    method public long toMinutes();
+    method public long toNanos();
+    method public java.time.Duration withNanos(int);
+    method public java.time.Duration withSeconds(long);
+    field public static final java.time.Duration ZERO;
+  }
+
+  public final class Instant implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.OffsetDateTime atOffset(java.time.ZoneOffset);
+    method public java.time.ZonedDateTime atZone(java.time.ZoneId);
+    method public int compareTo(java.time.Instant);
+    method public static java.time.Instant from(java.time.temporal.TemporalAccessor);
+    method public long getEpochSecond();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getNano();
+    method public boolean isAfter(java.time.Instant);
+    method public boolean isBefore(java.time.Instant);
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
+    method public java.time.Instant minusMillis(long);
+    method public java.time.Instant minusNanos(long);
+    method public java.time.Instant minusSeconds(long);
+    method public static java.time.Instant now();
+    method public static java.time.Instant now(java.time.Clock);
+    method public static java.time.Instant ofEpochMilli(long);
+    method public static java.time.Instant ofEpochSecond(long);
+    method public static java.time.Instant ofEpochSecond(long, long);
+    method public static java.time.Instant parse(java.lang.CharSequence);
+    method public java.time.Instant plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.Instant plusMillis(long);
+    method public java.time.Instant plusNanos(long);
+    method public java.time.Instant plusSeconds(long);
+    method public long toEpochMilli();
+    method public java.time.Instant truncatedTo(java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.Instant with(java.time.temporal.TemporalField, long);
+    field public static final java.time.Instant EPOCH;
+    field public static final java.time.Instant MAX;
+    field public static final java.time.Instant MIN;
+  }
+
+  public final class LocalDate implements java.time.chrono.ChronoLocalDate java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.LocalDateTime atStartOfDay();
+    method public java.time.ZonedDateTime atStartOfDay(java.time.ZoneId);
+    method public java.time.LocalDateTime atTime(int, int);
+    method public java.time.LocalDateTime atTime(int, int, int);
+    method public java.time.LocalDateTime atTime(int, int, int, int);
+    method public java.time.OffsetDateTime atTime(java.time.OffsetTime);
+    method public static java.time.LocalDate from(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.IsoChronology getChronology();
+    method public int getDayOfMonth();
+    method public java.time.DayOfWeek getDayOfWeek();
+    method public int getDayOfYear();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public java.time.Month getMonth();
+    method public int getMonthValue();
+    method public int getYear();
+    method public int lengthOfMonth();
+    method public java.time.LocalDate minusDays(long);
+    method public java.time.LocalDate minusMonths(long);
+    method public java.time.LocalDate minusWeeks(long);
+    method public java.time.LocalDate minusYears(long);
+    method public static java.time.LocalDate now();
+    method public static java.time.LocalDate now(java.time.ZoneId);
+    method public static java.time.LocalDate now(java.time.Clock);
+    method public static java.time.LocalDate of(int, java.time.Month, int);
+    method public static java.time.LocalDate of(int, int, int);
+    method public static java.time.LocalDate ofEpochDay(long);
+    method public static java.time.LocalDate ofYearDay(int, int);
+    method public static java.time.LocalDate parse(java.lang.CharSequence);
+    method public static java.time.LocalDate parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.LocalDate plusDays(long);
+    method public java.time.LocalDate plusMonths(long);
+    method public java.time.LocalDate plusWeeks(long);
+    method public java.time.LocalDate plusYears(long);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.Period until(java.time.chrono.ChronoLocalDate);
+    method public java.time.LocalDate withDayOfMonth(int);
+    method public java.time.LocalDate withDayOfYear(int);
+    method public java.time.LocalDate withMonth(int);
+    method public java.time.LocalDate withYear(int);
+    field public static final java.time.LocalDate MAX;
+    field public static final java.time.LocalDate MIN;
+  }
+
+  public final class LocalDateTime implements java.time.chrono.ChronoLocalDateTime java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.OffsetDateTime atOffset(java.time.ZoneOffset);
+    method public java.time.ZonedDateTime atZone(java.time.ZoneId);
+    method public static java.time.LocalDateTime from(java.time.temporal.TemporalAccessor);
+    method public int getDayOfMonth();
+    method public java.time.DayOfWeek getDayOfWeek();
+    method public int getDayOfYear();
+    method public int getHour();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getMinute();
+    method public java.time.Month getMonth();
+    method public int getMonthValue();
+    method public int getNano();
+    method public int getSecond();
+    method public int getYear();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public java.time.LocalDateTime minusDays(long);
+    method public java.time.LocalDateTime minusHours(long);
+    method public java.time.LocalDateTime minusMinutes(long);
+    method public java.time.LocalDateTime minusMonths(long);
+    method public java.time.LocalDateTime minusNanos(long);
+    method public java.time.LocalDateTime minusSeconds(long);
+    method public java.time.LocalDateTime minusWeeks(long);
+    method public java.time.LocalDateTime minusYears(long);
+    method public static java.time.LocalDateTime now();
+    method public static java.time.LocalDateTime now(java.time.ZoneId);
+    method public static java.time.LocalDateTime now(java.time.Clock);
+    method public static java.time.LocalDateTime of(int, java.time.Month, int, int, int);
+    method public static java.time.LocalDateTime of(int, java.time.Month, int, int, int, int);
+    method public static java.time.LocalDateTime of(int, java.time.Month, int, int, int, int, int);
+    method public static java.time.LocalDateTime of(int, int, int, int, int);
+    method public static java.time.LocalDateTime of(int, int, int, int, int, int);
+    method public static java.time.LocalDateTime of(int, int, int, int, int, int, int);
+    method public static java.time.LocalDateTime of(java.time.LocalDate, java.time.LocalTime);
+    method public static java.time.LocalDateTime ofEpochSecond(long, int, java.time.ZoneOffset);
+    method public static java.time.LocalDateTime ofInstant(java.time.Instant, java.time.ZoneId);
+    method public static java.time.LocalDateTime parse(java.lang.CharSequence);
+    method public static java.time.LocalDateTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.LocalDateTime plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.LocalDateTime plusDays(long);
+    method public java.time.LocalDateTime plusHours(long);
+    method public java.time.LocalDateTime plusMinutes(long);
+    method public java.time.LocalDateTime plusMonths(long);
+    method public java.time.LocalDateTime plusNanos(long);
+    method public java.time.LocalDateTime plusSeconds(long);
+    method public java.time.LocalDateTime plusWeeks(long);
+    method public java.time.LocalDateTime plusYears(long);
+    method public java.time.LocalDate toLocalDate();
+    method public java.time.LocalTime toLocalTime();
+    method public java.time.LocalDateTime truncatedTo(java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.LocalDateTime with(java.time.temporal.TemporalField, long);
+    method public java.time.LocalDateTime withDayOfMonth(int);
+    method public java.time.LocalDateTime withDayOfYear(int);
+    method public java.time.LocalDateTime withHour(int);
+    method public java.time.LocalDateTime withMinute(int);
+    method public java.time.LocalDateTime withMonth(int);
+    method public java.time.LocalDateTime withNano(int);
+    method public java.time.LocalDateTime withSecond(int);
+    method public java.time.LocalDateTime withYear(int);
+    field public static final java.time.LocalDateTime MAX;
+    field public static final java.time.LocalDateTime MIN;
+  }
+
+  public final class LocalTime implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.LocalDateTime atDate(java.time.LocalDate);
+    method public java.time.OffsetTime atOffset(java.time.ZoneOffset);
+    method public int compareTo(java.time.LocalTime);
+    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.LocalTime from(java.time.temporal.TemporalAccessor);
+    method public int getHour();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getMinute();
+    method public int getNano();
+    method public int getSecond();
+    method public boolean isAfter(java.time.LocalTime);
+    method public boolean isBefore(java.time.LocalTime);
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
+    method public java.time.LocalTime minusHours(long);
+    method public java.time.LocalTime minusMinutes(long);
+    method public java.time.LocalTime minusNanos(long);
+    method public java.time.LocalTime minusSeconds(long);
+    method public static java.time.LocalTime now();
+    method public static java.time.LocalTime now(java.time.ZoneId);
+    method public static java.time.LocalTime now(java.time.Clock);
+    method public static java.time.LocalTime of(int, int);
+    method public static java.time.LocalTime of(int, int, int);
+    method public static java.time.LocalTime of(int, int, int, int);
+    method public static java.time.LocalTime ofNanoOfDay(long);
+    method public static java.time.LocalTime ofSecondOfDay(long);
+    method public static java.time.LocalTime parse(java.lang.CharSequence);
+    method public static java.time.LocalTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.LocalTime plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.LocalTime plusHours(long);
+    method public java.time.LocalTime plusMinutes(long);
+    method public java.time.LocalTime plusNanos(long);
+    method public java.time.LocalTime plusSeconds(long);
+    method public long toNanoOfDay();
+    method public int toSecondOfDay();
+    method public java.time.LocalTime truncatedTo(java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.LocalTime with(java.time.temporal.TemporalField, long);
+    method public java.time.LocalTime withHour(int);
+    method public java.time.LocalTime withMinute(int);
+    method public java.time.LocalTime withNano(int);
+    method public java.time.LocalTime withSecond(int);
+    field public static final java.time.LocalTime MAX;
+    field public static final java.time.LocalTime MIDNIGHT;
+    field public static final java.time.LocalTime MIN;
+    field public static final java.time.LocalTime NOON;
+  }
+
+  public final class Month extends java.lang.Enum implements java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public int firstDayOfYear(boolean);
+    method public java.time.Month firstMonthOfQuarter();
+    method public static java.time.Month from(java.time.temporal.TemporalAccessor);
+    method public int get(java.time.temporal.TemporalField);
+    method public java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getValue();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public int length(boolean);
+    method public int maxLength();
+    method public int minLength();
+    method public java.time.Month minus(long);
+    method public static java.time.Month of(int);
+    method public java.time.Month plus(long);
+    method public <R> R query(java.time.temporal.TemporalQuery<R>);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public static java.time.Month valueOf(java.lang.String);
+    method public static final java.time.Month[] values();
+    enum_constant public static final java.time.Month APRIL;
+    enum_constant public static final java.time.Month AUGUST;
+    enum_constant public static final java.time.Month DECEMBER;
+    enum_constant public static final java.time.Month FEBRUARY;
+    enum_constant public static final java.time.Month JANUARY;
+    enum_constant public static final java.time.Month JULY;
+    enum_constant public static final java.time.Month JUNE;
+    enum_constant public static final java.time.Month MARCH;
+    enum_constant public static final java.time.Month MAY;
+    enum_constant public static final java.time.Month NOVEMBER;
+    enum_constant public static final java.time.Month OCTOBER;
+    enum_constant public static final java.time.Month SEPTEMBER;
+  }
+
+  public final class MonthDay implements java.lang.Comparable java.io.Serializable java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.LocalDate atYear(int);
+    method public int compareTo(java.time.MonthDay);
+    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.MonthDay from(java.time.temporal.TemporalAccessor);
+    method public int getDayOfMonth();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public java.time.Month getMonth();
+    method public int getMonthValue();
+    method public boolean isAfter(java.time.MonthDay);
+    method public boolean isBefore(java.time.MonthDay);
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isValidYear(int);
+    method public static java.time.MonthDay now();
+    method public static java.time.MonthDay now(java.time.ZoneId);
+    method public static java.time.MonthDay now(java.time.Clock);
+    method public static java.time.MonthDay of(java.time.Month, int);
+    method public static java.time.MonthDay of(int, int);
+    method public static java.time.MonthDay parse(java.lang.CharSequence);
+    method public static java.time.MonthDay parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.MonthDay with(java.time.Month);
+    method public java.time.MonthDay withDayOfMonth(int);
+    method public java.time.MonthDay withMonth(int);
+  }
+
+  public final class OffsetDateTime implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.ZonedDateTime atZoneSameInstant(java.time.ZoneId);
+    method public java.time.ZonedDateTime atZoneSimilarLocal(java.time.ZoneId);
+    method public int compareTo(java.time.OffsetDateTime);
+    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.OffsetDateTime from(java.time.temporal.TemporalAccessor);
+    method public int getDayOfMonth();
+    method public java.time.DayOfWeek getDayOfWeek();
+    method public int getDayOfYear();
+    method public int getHour();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getMinute();
+    method public java.time.Month getMonth();
+    method public int getMonthValue();
+    method public int getNano();
+    method public java.time.ZoneOffset getOffset();
+    method public int getSecond();
+    method public int getYear();
+    method public boolean isAfter(java.time.OffsetDateTime);
+    method public boolean isBefore(java.time.OffsetDateTime);
+    method public boolean isEqual(java.time.OffsetDateTime);
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
+    method public java.time.OffsetDateTime minusDays(long);
+    method public java.time.OffsetDateTime minusHours(long);
+    method public java.time.OffsetDateTime minusMinutes(long);
+    method public java.time.OffsetDateTime minusMonths(long);
+    method public java.time.OffsetDateTime minusNanos(long);
+    method public java.time.OffsetDateTime minusSeconds(long);
+    method public java.time.OffsetDateTime minusWeeks(long);
+    method public java.time.OffsetDateTime minusYears(long);
+    method public static java.time.OffsetDateTime now();
+    method public static java.time.OffsetDateTime now(java.time.ZoneId);
+    method public static java.time.OffsetDateTime now(java.time.Clock);
+    method public static java.time.OffsetDateTime of(java.time.LocalDate, java.time.LocalTime, java.time.ZoneOffset);
+    method public static java.time.OffsetDateTime of(java.time.LocalDateTime, java.time.ZoneOffset);
+    method public static java.time.OffsetDateTime of(int, int, int, int, int, int, int, java.time.ZoneOffset);
+    method public static java.time.OffsetDateTime ofInstant(java.time.Instant, java.time.ZoneId);
+    method public static java.time.OffsetDateTime parse(java.lang.CharSequence);
+    method public static java.time.OffsetDateTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.OffsetDateTime plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.OffsetDateTime plusDays(long);
+    method public java.time.OffsetDateTime plusHours(long);
+    method public java.time.OffsetDateTime plusMinutes(long);
+    method public java.time.OffsetDateTime plusMonths(long);
+    method public java.time.OffsetDateTime plusNanos(long);
+    method public java.time.OffsetDateTime plusSeconds(long);
+    method public java.time.OffsetDateTime plusWeeks(long);
+    method public java.time.OffsetDateTime plusYears(long);
+    method public static java.util.Comparator<java.time.OffsetDateTime> timeLineOrder();
+    method public long toEpochSecond();
+    method public java.time.Instant toInstant();
+    method public java.time.LocalDate toLocalDate();
+    method public java.time.LocalDateTime toLocalDateTime();
+    method public java.time.LocalTime toLocalTime();
+    method public java.time.OffsetTime toOffsetTime();
+    method public java.time.ZonedDateTime toZonedDateTime();
+    method public java.time.OffsetDateTime truncatedTo(java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.OffsetDateTime with(java.time.temporal.TemporalField, long);
+    method public java.time.OffsetDateTime withDayOfMonth(int);
+    method public java.time.OffsetDateTime withDayOfYear(int);
+    method public java.time.OffsetDateTime withHour(int);
+    method public java.time.OffsetDateTime withMinute(int);
+    method public java.time.OffsetDateTime withMonth(int);
+    method public java.time.OffsetDateTime withNano(int);
+    method public java.time.OffsetDateTime withOffsetSameInstant(java.time.ZoneOffset);
+    method public java.time.OffsetDateTime withOffsetSameLocal(java.time.ZoneOffset);
+    method public java.time.OffsetDateTime withSecond(int);
+    method public java.time.OffsetDateTime withYear(int);
+    field public static final java.time.OffsetDateTime MAX;
+    field public static final java.time.OffsetDateTime MIN;
+  }
+
+  public final class OffsetTime implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.OffsetDateTime atDate(java.time.LocalDate);
+    method public int compareTo(java.time.OffsetTime);
+    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.OffsetTime from(java.time.temporal.TemporalAccessor);
+    method public int getHour();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getMinute();
+    method public int getNano();
+    method public java.time.ZoneOffset getOffset();
+    method public int getSecond();
+    method public boolean isAfter(java.time.OffsetTime);
+    method public boolean isBefore(java.time.OffsetTime);
+    method public boolean isEqual(java.time.OffsetTime);
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
+    method public java.time.OffsetTime minusHours(long);
+    method public java.time.OffsetTime minusMinutes(long);
+    method public java.time.OffsetTime minusNanos(long);
+    method public java.time.OffsetTime minusSeconds(long);
+    method public static java.time.OffsetTime now();
+    method public static java.time.OffsetTime now(java.time.ZoneId);
+    method public static java.time.OffsetTime now(java.time.Clock);
+    method public static java.time.OffsetTime of(java.time.LocalTime, java.time.ZoneOffset);
+    method public static java.time.OffsetTime of(int, int, int, int, java.time.ZoneOffset);
+    method public static java.time.OffsetTime ofInstant(java.time.Instant, java.time.ZoneId);
+    method public static java.time.OffsetTime parse(java.lang.CharSequence);
+    method public static java.time.OffsetTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.OffsetTime plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.OffsetTime plusHours(long);
+    method public java.time.OffsetTime plusMinutes(long);
+    method public java.time.OffsetTime plusNanos(long);
+    method public java.time.OffsetTime plusSeconds(long);
+    method public java.time.LocalTime toLocalTime();
+    method public java.time.OffsetTime truncatedTo(java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.OffsetTime with(java.time.temporal.TemporalField, long);
+    method public java.time.OffsetTime withHour(int);
+    method public java.time.OffsetTime withMinute(int);
+    method public java.time.OffsetTime withNano(int);
+    method public java.time.OffsetTime withOffsetSameInstant(java.time.ZoneOffset);
+    method public java.time.OffsetTime withOffsetSameLocal(java.time.ZoneOffset);
+    method public java.time.OffsetTime withSecond(int);
+    field public static final java.time.OffsetTime MAX;
+    field public static final java.time.OffsetTime MIN;
+  }
+
+  public final class Period implements java.time.chrono.ChronoPeriod java.io.Serializable {
+    method public java.time.temporal.Temporal addTo(java.time.temporal.Temporal);
+    method public static java.time.Period between(java.time.LocalDate, java.time.LocalDate);
+    method public static java.time.Period from(java.time.temporal.TemporalAmount);
+    method public long get(java.time.temporal.TemporalUnit);
+    method public java.time.chrono.IsoChronology getChronology();
+    method public int getDays();
+    method public int getMonths();
+    method public java.util.List<java.time.temporal.TemporalUnit> getUnits();
+    method public int getYears();
+    method public java.time.Period minus(java.time.temporal.TemporalAmount);
+    method public java.time.Period minusDays(long);
+    method public java.time.Period minusMonths(long);
+    method public java.time.Period minusYears(long);
+    method public java.time.Period multipliedBy(int);
+    method public java.time.Period normalized();
+    method public static java.time.Period of(int, int, int);
+    method public static java.time.Period ofDays(int);
+    method public static java.time.Period ofMonths(int);
+    method public static java.time.Period ofWeeks(int);
+    method public static java.time.Period ofYears(int);
+    method public static java.time.Period parse(java.lang.CharSequence);
+    method public java.time.Period plus(java.time.temporal.TemporalAmount);
+    method public java.time.Period plusDays(long);
+    method public java.time.Period plusMonths(long);
+    method public java.time.Period plusYears(long);
+    method public java.time.temporal.Temporal subtractFrom(java.time.temporal.Temporal);
+    method public long toTotalMonths();
+    method public java.time.Period withDays(int);
+    method public java.time.Period withMonths(int);
+    method public java.time.Period withYears(int);
+    field public static final java.time.Period ZERO;
+  }
+
+  public final class Year implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.LocalDate atDay(int);
+    method public java.time.YearMonth atMonth(java.time.Month);
+    method public java.time.YearMonth atMonth(int);
+    method public java.time.LocalDate atMonthDay(java.time.MonthDay);
+    method public int compareTo(java.time.Year);
+    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.Year from(java.time.temporal.TemporalAccessor);
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getValue();
+    method public boolean isAfter(java.time.Year);
+    method public boolean isBefore(java.time.Year);
+    method public static boolean isLeap(long);
+    method public boolean isLeap();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
+    method public boolean isValidMonthDay(java.time.MonthDay);
+    method public int length();
+    method public java.time.Year minusYears(long);
+    method public static java.time.Year now();
+    method public static java.time.Year now(java.time.ZoneId);
+    method public static java.time.Year now(java.time.Clock);
+    method public static java.time.Year of(int);
+    method public static java.time.Year parse(java.lang.CharSequence);
+    method public static java.time.Year parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.Year plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.Year plusYears(long);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.Year with(java.time.temporal.TemporalField, long);
+    field public static final int MAX_VALUE = 999999999; // 0x3b9ac9ff
+    field public static final int MIN_VALUE = -999999999; // 0xc4653601
+  }
+
+  public final class YearMonth implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.LocalDate atDay(int);
+    method public java.time.LocalDate atEndOfMonth();
+    method public int compareTo(java.time.YearMonth);
+    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.YearMonth from(java.time.temporal.TemporalAccessor);
+    method public long getLong(java.time.temporal.TemporalField);
+    method public java.time.Month getMonth();
+    method public int getMonthValue();
+    method public int getYear();
+    method public boolean isAfter(java.time.YearMonth);
+    method public boolean isBefore(java.time.YearMonth);
+    method public boolean isLeapYear();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
+    method public boolean isValidDay(int);
+    method public int lengthOfMonth();
+    method public int lengthOfYear();
+    method public java.time.YearMonth minusMonths(long);
+    method public java.time.YearMonth minusYears(long);
+    method public static java.time.YearMonth now();
+    method public static java.time.YearMonth now(java.time.ZoneId);
+    method public static java.time.YearMonth now(java.time.Clock);
+    method public static java.time.YearMonth of(int, java.time.Month);
+    method public static java.time.YearMonth of(int, int);
+    method public static java.time.YearMonth parse(java.lang.CharSequence);
+    method public static java.time.YearMonth parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.YearMonth plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.YearMonth plusMonths(long);
+    method public java.time.YearMonth plusYears(long);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.YearMonth with(java.time.temporal.TemporalField, long);
+    method public java.time.YearMonth withMonth(int);
+    method public java.time.YearMonth withYear(int);
+  }
+
+  public abstract class ZoneId implements java.io.Serializable {
+    method public static java.time.ZoneId from(java.time.temporal.TemporalAccessor);
+    method public static java.util.Set<java.lang.String> getAvailableZoneIds();
+    method public java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public abstract java.lang.String getId();
+    method public abstract java.time.zone.ZoneRules getRules();
+    method public java.time.ZoneId normalized();
+    method public static java.time.ZoneId of(java.lang.String, java.util.Map<java.lang.String, java.lang.String>);
+    method public static java.time.ZoneId of(java.lang.String);
+    method public static java.time.ZoneId ofOffset(java.lang.String, java.time.ZoneOffset);
+    method public static java.time.ZoneId systemDefault();
+    field public static final java.util.Map<java.lang.String, java.lang.String> SHORT_IDS;
+  }
+
+  public final class ZoneOffset extends java.time.ZoneId implements java.lang.Comparable java.io.Serializable java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public int compareTo(java.time.ZoneOffset);
+    method public static java.time.ZoneOffset from(java.time.temporal.TemporalAccessor);
+    method public int get(java.time.temporal.TemporalField);
+    method public java.lang.String getId();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public java.time.zone.ZoneRules getRules();
+    method public int getTotalSeconds();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public static java.time.ZoneOffset of(java.lang.String);
+    method public static java.time.ZoneOffset ofHours(int);
+    method public static java.time.ZoneOffset ofHoursMinutes(int, int);
+    method public static java.time.ZoneOffset ofHoursMinutesSeconds(int, int, int);
+    method public static java.time.ZoneOffset ofTotalSeconds(int);
+    method public <R> R query(java.time.temporal.TemporalQuery<R>);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    field public static final java.time.ZoneOffset MAX;
+    field public static final java.time.ZoneOffset MIN;
+    field public static final java.time.ZoneOffset UTC;
+  }
+
+  public final class ZonedDateTime implements java.time.chrono.ChronoZonedDateTime java.io.Serializable java.time.temporal.Temporal {
+    method public static java.time.ZonedDateTime from(java.time.temporal.TemporalAccessor);
+    method public int getDayOfMonth();
+    method public java.time.DayOfWeek getDayOfWeek();
+    method public int getDayOfYear();
+    method public int getHour();
+    method public int getMinute();
+    method public java.time.Month getMonth();
+    method public int getMonthValue();
+    method public int getNano();
+    method public java.time.ZoneOffset getOffset();
+    method public int getSecond();
+    method public int getYear();
+    method public java.time.ZoneId getZone();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public java.time.ZonedDateTime minusDays(long);
+    method public java.time.ZonedDateTime minusHours(long);
+    method public java.time.ZonedDateTime minusMinutes(long);
+    method public java.time.ZonedDateTime minusMonths(long);
+    method public java.time.ZonedDateTime minusNanos(long);
+    method public java.time.ZonedDateTime minusSeconds(long);
+    method public java.time.ZonedDateTime minusWeeks(long);
+    method public java.time.ZonedDateTime minusYears(long);
+    method public static java.time.ZonedDateTime now();
+    method public static java.time.ZonedDateTime now(java.time.ZoneId);
+    method public static java.time.ZonedDateTime now(java.time.Clock);
+    method public static java.time.ZonedDateTime of(java.time.LocalDate, java.time.LocalTime, java.time.ZoneId);
+    method public static java.time.ZonedDateTime of(java.time.LocalDateTime, java.time.ZoneId);
+    method public static java.time.ZonedDateTime of(int, int, int, int, int, int, int, java.time.ZoneId);
+    method public static java.time.ZonedDateTime ofInstant(java.time.Instant, java.time.ZoneId);
+    method public static java.time.ZonedDateTime ofInstant(java.time.LocalDateTime, java.time.ZoneOffset, java.time.ZoneId);
+    method public static java.time.ZonedDateTime ofLocal(java.time.LocalDateTime, java.time.ZoneId, java.time.ZoneOffset);
+    method public static java.time.ZonedDateTime ofStrict(java.time.LocalDateTime, java.time.ZoneOffset, java.time.ZoneId);
+    method public static java.time.ZonedDateTime parse(java.lang.CharSequence);
+    method public static java.time.ZonedDateTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.ZonedDateTime plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.ZonedDateTime plusDays(long);
+    method public java.time.ZonedDateTime plusHours(long);
+    method public java.time.ZonedDateTime plusMinutes(long);
+    method public java.time.ZonedDateTime plusMonths(long);
+    method public java.time.ZonedDateTime plusNanos(long);
+    method public java.time.ZonedDateTime plusSeconds(long);
+    method public java.time.ZonedDateTime plusWeeks(long);
+    method public java.time.ZonedDateTime plusYears(long);
+    method public java.time.LocalDateTime toLocalDateTime();
+    method public java.time.OffsetDateTime toOffsetDateTime();
+    method public java.time.ZonedDateTime truncatedTo(java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.ZonedDateTime with(java.time.temporal.TemporalField, long);
+    method public java.time.ZonedDateTime withDayOfMonth(int);
+    method public java.time.ZonedDateTime withDayOfYear(int);
+    method public java.time.ZonedDateTime withEarlierOffsetAtOverlap();
+    method public java.time.ZonedDateTime withFixedOffsetZone();
+    method public java.time.ZonedDateTime withHour(int);
+    method public java.time.ZonedDateTime withLaterOffsetAtOverlap();
+    method public java.time.ZonedDateTime withMinute(int);
+    method public java.time.ZonedDateTime withMonth(int);
+    method public java.time.ZonedDateTime withNano(int);
+    method public java.time.ZonedDateTime withSecond(int);
+    method public java.time.ZonedDateTime withYear(int);
+    method public java.time.ZonedDateTime withZoneSameInstant(java.time.ZoneId);
+    method public java.time.ZonedDateTime withZoneSameLocal(java.time.ZoneId);
+  }
+
+}
+
+package java.time.chrono {
+
+  public abstract class AbstractChronology implements java.time.chrono.Chronology {
+    ctor protected AbstractChronology();
+    method public int compareTo(java.time.chrono.Chronology);
+    method public java.time.chrono.ChronoLocalDate resolveDate(java.util.Map<java.time.temporal.TemporalField, java.lang.Long>, java.time.format.ResolverStyle);
+  }
+
+  public abstract interface ChronoLocalDate implements java.lang.Comparable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public default java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public default java.time.chrono.ChronoLocalDateTime<?> atTime(java.time.LocalTime);
+    method public default int compareTo(java.time.chrono.ChronoLocalDate);
+    method public abstract boolean equals(java.lang.Object);
+    method public default java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.chrono.ChronoLocalDate from(java.time.temporal.TemporalAccessor);
+    method public abstract java.time.chrono.Chronology getChronology();
+    method public default java.time.chrono.Era getEra();
+    method public abstract int hashCode();
+    method public default boolean isAfter(java.time.chrono.ChronoLocalDate);
+    method public default boolean isBefore(java.time.chrono.ChronoLocalDate);
+    method public default boolean isEqual(java.time.chrono.ChronoLocalDate);
+    method public default boolean isLeapYear();
+    method public default boolean isSupported(java.time.temporal.TemporalField);
+    method public default boolean isSupported(java.time.temporal.TemporalUnit);
+    method public abstract int lengthOfMonth();
+    method public default int lengthOfYear();
+    method public default java.time.chrono.ChronoLocalDate plus(long, java.time.temporal.TemporalUnit);
+    method public static java.util.Comparator<java.time.chrono.ChronoLocalDate> timeLineOrder();
+    method public default long toEpochDay();
+    method public abstract java.lang.String toString();
+    method public abstract long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public abstract java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+    method public default java.time.chrono.ChronoLocalDate with(java.time.temporal.TemporalField, long);
+  }
+
+   abstract class ChronoLocalDateImpl<D extends java.time.chrono.ChronoLocalDate> implements java.time.chrono.ChronoLocalDate java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+  }
+
+  public abstract interface ChronoLocalDateTime<D extends java.time.chrono.ChronoLocalDate> implements java.lang.Comparable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public default java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> atZone(java.time.ZoneId);
+    method public default int compareTo(java.time.chrono.ChronoLocalDateTime<?>);
+    method public abstract boolean equals(java.lang.Object);
+    method public default java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.chrono.ChronoLocalDateTime<?> from(java.time.temporal.TemporalAccessor);
+    method public default java.time.chrono.Chronology getChronology();
+    method public abstract int hashCode();
+    method public default boolean isAfter(java.time.chrono.ChronoLocalDateTime<?>);
+    method public default boolean isBefore(java.time.chrono.ChronoLocalDateTime<?>);
+    method public default boolean isEqual(java.time.chrono.ChronoLocalDateTime<?>);
+    method public abstract boolean isSupported(java.time.temporal.TemporalField);
+    method public default boolean isSupported(java.time.temporal.TemporalUnit);
+    method public abstract java.time.chrono.ChronoLocalDateTime<D> plus(long, java.time.temporal.TemporalUnit);
+    method public static java.util.Comparator<java.time.chrono.ChronoLocalDateTime<?>> timeLineOrder();
+    method public default long toEpochSecond(java.time.ZoneOffset);
+    method public default java.time.Instant toInstant(java.time.ZoneOffset);
+    method public abstract D toLocalDate();
+    method public abstract java.time.LocalTime toLocalTime();
+    method public abstract java.lang.String toString();
+    method public abstract java.time.chrono.ChronoLocalDateTime<D> with(java.time.temporal.TemporalField, long);
+  }
+
+  public abstract interface ChronoPeriod implements java.time.temporal.TemporalAmount {
+    method public abstract java.time.temporal.Temporal addTo(java.time.temporal.Temporal);
+    method public static java.time.chrono.ChronoPeriod between(java.time.chrono.ChronoLocalDate, java.time.chrono.ChronoLocalDate);
+    method public abstract boolean equals(java.lang.Object);
+    method public abstract long get(java.time.temporal.TemporalUnit);
+    method public abstract java.time.chrono.Chronology getChronology();
+    method public abstract java.util.List<java.time.temporal.TemporalUnit> getUnits();
+    method public abstract int hashCode();
+    method public default boolean isNegative();
+    method public default boolean isZero();
+    method public abstract java.time.chrono.ChronoPeriod minus(java.time.temporal.TemporalAmount);
+    method public abstract java.time.chrono.ChronoPeriod multipliedBy(int);
+    method public default java.time.chrono.ChronoPeriod negated();
+    method public abstract java.time.chrono.ChronoPeriod normalized();
+    method public abstract java.time.chrono.ChronoPeriod plus(java.time.temporal.TemporalAmount);
+    method public abstract java.time.temporal.Temporal subtractFrom(java.time.temporal.Temporal);
+    method public abstract java.lang.String toString();
+  }
+
+  public abstract interface ChronoZonedDateTime<D extends java.time.chrono.ChronoLocalDate> implements java.lang.Comparable java.time.temporal.Temporal {
+    method public default int compareTo(java.time.chrono.ChronoZonedDateTime<?>);
+    method public abstract boolean equals(java.lang.Object);
+    method public default java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.chrono.ChronoZonedDateTime<?> from(java.time.temporal.TemporalAccessor);
+    method public default java.time.chrono.Chronology getChronology();
+    method public default long getLong(java.time.temporal.TemporalField);
+    method public abstract java.time.ZoneOffset getOffset();
+    method public abstract java.time.ZoneId getZone();
+    method public abstract int hashCode();
+    method public default boolean isAfter(java.time.chrono.ChronoZonedDateTime<?>);
+    method public default boolean isBefore(java.time.chrono.ChronoZonedDateTime<?>);
+    method public default boolean isEqual(java.time.chrono.ChronoZonedDateTime<?>);
+    method public abstract boolean isSupported(java.time.temporal.TemporalField);
+    method public default boolean isSupported(java.time.temporal.TemporalUnit);
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> plus(long, java.time.temporal.TemporalUnit);
+    method public static java.util.Comparator<java.time.chrono.ChronoZonedDateTime<?>> timeLineOrder();
+    method public default long toEpochSecond();
+    method public default java.time.Instant toInstant();
+    method public default D toLocalDate();
+    method public abstract java.time.chrono.ChronoLocalDateTime<D> toLocalDateTime();
+    method public default java.time.LocalTime toLocalTime();
+    method public abstract java.lang.String toString();
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> with(java.time.temporal.TemporalField, long);
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> withEarlierOffsetAtOverlap();
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> withLaterOffsetAtOverlap();
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> withZoneSameInstant(java.time.ZoneId);
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> withZoneSameLocal(java.time.ZoneId);
+  }
+
+  public abstract interface Chronology implements java.lang.Comparable {
+    method public abstract int compareTo(java.time.chrono.Chronology);
+    method public default java.time.chrono.ChronoLocalDate date(java.time.chrono.Era, int, int, int);
+    method public abstract java.time.chrono.ChronoLocalDate date(int, int, int);
+    method public abstract java.time.chrono.ChronoLocalDate date(java.time.temporal.TemporalAccessor);
+    method public abstract java.time.chrono.ChronoLocalDate dateEpochDay(long);
+    method public default java.time.chrono.ChronoLocalDate dateNow();
+    method public default java.time.chrono.ChronoLocalDate dateNow(java.time.ZoneId);
+    method public default java.time.chrono.ChronoLocalDate dateNow(java.time.Clock);
+    method public default java.time.chrono.ChronoLocalDate dateYearDay(java.time.chrono.Era, int, int);
+    method public abstract java.time.chrono.ChronoLocalDate dateYearDay(int, int);
+    method public abstract boolean equals(java.lang.Object);
+    method public abstract java.time.chrono.Era eraOf(int);
+    method public abstract java.util.List<java.time.chrono.Era> eras();
+    method public static java.time.chrono.Chronology from(java.time.temporal.TemporalAccessor);
+    method public static java.util.Set<java.time.chrono.Chronology> getAvailableChronologies();
+    method public abstract java.lang.String getCalendarType();
+    method public default java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public abstract java.lang.String getId();
+    method public abstract int hashCode();
+    method public abstract boolean isLeapYear(long);
+    method public default java.time.chrono.ChronoLocalDateTime<? extends java.time.chrono.ChronoLocalDate> localDateTime(java.time.temporal.TemporalAccessor);
+    method public static java.time.chrono.Chronology of(java.lang.String);
+    method public static java.time.chrono.Chronology ofLocale(java.util.Locale);
+    method public default java.time.chrono.ChronoPeriod period(int, int, int);
+    method public abstract int prolepticYear(java.time.chrono.Era, int);
+    method public abstract java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public abstract java.time.chrono.ChronoLocalDate resolveDate(java.util.Map<java.time.temporal.TemporalField, java.lang.Long>, java.time.format.ResolverStyle);
+    method public abstract java.lang.String toString();
+    method public default java.time.chrono.ChronoZonedDateTime<? extends java.time.chrono.ChronoLocalDate> zonedDateTime(java.time.temporal.TemporalAccessor);
+    method public default java.time.chrono.ChronoZonedDateTime<? extends java.time.chrono.ChronoLocalDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
+  }
+
+  public abstract interface Era implements java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+    method public default java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public default java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public default long getLong(java.time.temporal.TemporalField);
+    method public abstract int getValue();
+    method public default boolean isSupported(java.time.temporal.TemporalField);
+  }
+
+  public final class HijrahChronology extends java.time.chrono.AbstractChronology implements java.io.Serializable {
+    method public java.time.chrono.HijrahDate date(java.time.chrono.Era, int, int, int);
+    method public java.time.chrono.HijrahDate date(int, int, int);
+    method public java.time.chrono.HijrahDate date(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.HijrahDate dateEpochDay(long);
+    method public java.time.chrono.HijrahDate dateNow();
+    method public java.time.chrono.HijrahDate dateNow(java.time.ZoneId);
+    method public java.time.chrono.HijrahDate dateNow(java.time.Clock);
+    method public java.time.chrono.HijrahDate dateYearDay(java.time.chrono.Era, int, int);
+    method public java.time.chrono.HijrahDate dateYearDay(int, int);
+    method public java.time.chrono.HijrahEra eraOf(int);
+    method public java.util.List<java.time.chrono.Era> eras();
+    method public java.lang.String getCalendarType();
+    method public java.lang.String getId();
+    method public boolean isLeapYear(long);
+    method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.HijrahDate> localDateTime(java.time.temporal.TemporalAccessor);
+    method public int prolepticYear(java.time.chrono.Era, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.HijrahDate> zonedDateTime(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.HijrahDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
+    field public static final java.time.chrono.HijrahChronology INSTANCE;
+  }
+
+  public final class HijrahDate extends java.time.chrono.ChronoLocalDateImpl implements java.time.chrono.ChronoLocalDate java.io.Serializable {
+    method public final java.time.chrono.ChronoLocalDateTime<java.time.chrono.HijrahDate> atTime(java.time.LocalTime);
+    method public static java.time.chrono.HijrahDate from(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.HijrahChronology getChronology();
+    method public java.time.chrono.HijrahEra getEra();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public boolean isLeapYear();
+    method public int lengthOfMonth();
+    method public int lengthOfYear();
+    method public static java.time.chrono.HijrahDate now();
+    method public static java.time.chrono.HijrahDate now(java.time.ZoneId);
+    method public static java.time.chrono.HijrahDate now(java.time.Clock);
+    method public static java.time.chrono.HijrahDate of(int, int, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public long toEpochDay();
+    method public java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+    method public java.time.chrono.HijrahDate withVariant(java.time.chrono.HijrahChronology);
+  }
+
+  public final class HijrahEra extends java.lang.Enum implements java.time.chrono.Era {
+    method public int getValue();
+    method public static java.time.chrono.HijrahEra of(int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public static java.time.chrono.HijrahEra valueOf(java.lang.String);
+    method public static final java.time.chrono.HijrahEra[] values();
+    enum_constant public static final java.time.chrono.HijrahEra AH;
+  }
+
+  public final class IsoChronology extends java.time.chrono.AbstractChronology implements java.io.Serializable {
+    method public java.time.LocalDate date(java.time.chrono.Era, int, int, int);
+    method public java.time.LocalDate date(int, int, int);
+    method public java.time.LocalDate date(java.time.temporal.TemporalAccessor);
+    method public java.time.LocalDate dateEpochDay(long);
+    method public java.time.LocalDate dateNow();
+    method public java.time.LocalDate dateNow(java.time.ZoneId);
+    method public java.time.LocalDate dateNow(java.time.Clock);
+    method public java.time.LocalDate dateYearDay(java.time.chrono.Era, int, int);
+    method public java.time.LocalDate dateYearDay(int, int);
+    method public java.time.chrono.IsoEra eraOf(int);
+    method public java.util.List<java.time.chrono.Era> eras();
+    method public java.lang.String getCalendarType();
+    method public java.lang.String getId();
+    method public boolean isLeapYear(long);
+    method public java.time.LocalDateTime localDateTime(java.time.temporal.TemporalAccessor);
+    method public java.time.Period period(int, int, int);
+    method public int prolepticYear(java.time.chrono.Era, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public java.time.ZonedDateTime zonedDateTime(java.time.temporal.TemporalAccessor);
+    method public java.time.ZonedDateTime zonedDateTime(java.time.Instant, java.time.ZoneId);
+    field public static final java.time.chrono.IsoChronology INSTANCE;
+  }
+
+  public final class IsoEra extends java.lang.Enum implements java.time.chrono.Era {
+    method public int getValue();
+    method public static java.time.chrono.IsoEra of(int);
+    method public static java.time.chrono.IsoEra valueOf(java.lang.String);
+    method public static final java.time.chrono.IsoEra[] values();
+    enum_constant public static final java.time.chrono.IsoEra BCE;
+    enum_constant public static final java.time.chrono.IsoEra CE;
+  }
+
+  public final class JapaneseChronology extends java.time.chrono.AbstractChronology implements java.io.Serializable {
+    method public java.time.chrono.JapaneseDate date(java.time.chrono.Era, int, int, int);
+    method public java.time.chrono.JapaneseDate date(int, int, int);
+    method public java.time.chrono.JapaneseDate date(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.JapaneseDate dateEpochDay(long);
+    method public java.time.chrono.JapaneseDate dateNow();
+    method public java.time.chrono.JapaneseDate dateNow(java.time.ZoneId);
+    method public java.time.chrono.JapaneseDate dateNow(java.time.Clock);
+    method public java.time.chrono.JapaneseDate dateYearDay(java.time.chrono.Era, int, int);
+    method public java.time.chrono.JapaneseDate dateYearDay(int, int);
+    method public java.time.chrono.JapaneseEra eraOf(int);
+    method public java.util.List<java.time.chrono.Era> eras();
+    method public java.lang.String getCalendarType();
+    method public java.lang.String getId();
+    method public boolean isLeapYear(long);
+    method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.JapaneseDate> localDateTime(java.time.temporal.TemporalAccessor);
+    method public int prolepticYear(java.time.chrono.Era, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.JapaneseDate> zonedDateTime(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.JapaneseDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
+    field public static final java.time.chrono.JapaneseChronology INSTANCE;
+  }
+
+  public final class JapaneseDate extends java.time.chrono.ChronoLocalDateImpl implements java.time.chrono.ChronoLocalDate java.io.Serializable {
+    method public final java.time.chrono.ChronoLocalDateTime<java.time.chrono.JapaneseDate> atTime(java.time.LocalTime);
+    method public static java.time.chrono.JapaneseDate from(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.JapaneseChronology getChronology();
+    method public java.time.chrono.JapaneseEra getEra();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public int lengthOfMonth();
+    method public int lengthOfYear();
+    method public static java.time.chrono.JapaneseDate now();
+    method public static java.time.chrono.JapaneseDate now(java.time.ZoneId);
+    method public static java.time.chrono.JapaneseDate now(java.time.Clock);
+    method public static java.time.chrono.JapaneseDate of(java.time.chrono.JapaneseEra, int, int, int);
+    method public static java.time.chrono.JapaneseDate of(int, int, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public long toEpochDay();
+    method public java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+  }
+
+  public final class JapaneseEra implements java.time.chrono.Era java.io.Serializable {
+    method public int getValue();
+    method public static java.time.chrono.JapaneseEra of(int);
+    method public static java.time.chrono.JapaneseEra valueOf(java.lang.String);
+    method public static java.time.chrono.JapaneseEra[] values();
+    field public static final java.time.chrono.JapaneseEra HEISEI;
+    field public static final java.time.chrono.JapaneseEra MEIJI;
+    field public static final java.time.chrono.JapaneseEra SHOWA;
+    field public static final java.time.chrono.JapaneseEra TAISHO;
+  }
+
+  public final class MinguoChronology extends java.time.chrono.AbstractChronology implements java.io.Serializable {
+    method public java.time.chrono.MinguoDate date(java.time.chrono.Era, int, int, int);
+    method public java.time.chrono.MinguoDate date(int, int, int);
+    method public java.time.chrono.MinguoDate date(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.MinguoDate dateEpochDay(long);
+    method public java.time.chrono.MinguoDate dateNow();
+    method public java.time.chrono.MinguoDate dateNow(java.time.ZoneId);
+    method public java.time.chrono.MinguoDate dateNow(java.time.Clock);
+    method public java.time.chrono.MinguoDate dateYearDay(java.time.chrono.Era, int, int);
+    method public java.time.chrono.MinguoDate dateYearDay(int, int);
+    method public java.time.chrono.MinguoEra eraOf(int);
+    method public java.util.List<java.time.chrono.Era> eras();
+    method public java.lang.String getCalendarType();
+    method public java.lang.String getId();
+    method public boolean isLeapYear(long);
+    method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.MinguoDate> localDateTime(java.time.temporal.TemporalAccessor);
+    method public int prolepticYear(java.time.chrono.Era, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.MinguoDate> zonedDateTime(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.MinguoDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
+    field public static final java.time.chrono.MinguoChronology INSTANCE;
+  }
+
+  public final class MinguoDate extends java.time.chrono.ChronoLocalDateImpl implements java.time.chrono.ChronoLocalDate java.io.Serializable {
+    method public final java.time.chrono.ChronoLocalDateTime<java.time.chrono.MinguoDate> atTime(java.time.LocalTime);
+    method public static java.time.chrono.MinguoDate from(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.MinguoChronology getChronology();
+    method public java.time.chrono.MinguoEra getEra();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int lengthOfMonth();
+    method public static java.time.chrono.MinguoDate now();
+    method public static java.time.chrono.MinguoDate now(java.time.ZoneId);
+    method public static java.time.chrono.MinguoDate now(java.time.Clock);
+    method public static java.time.chrono.MinguoDate of(int, int, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public long toEpochDay();
+    method public java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+  }
+
+  public final class MinguoEra extends java.lang.Enum implements java.time.chrono.Era {
+    method public int getValue();
+    method public static java.time.chrono.MinguoEra of(int);
+    method public static java.time.chrono.MinguoEra valueOf(java.lang.String);
+    method public static final java.time.chrono.MinguoEra[] values();
+    enum_constant public static final java.time.chrono.MinguoEra BEFORE_ROC;
+    enum_constant public static final java.time.chrono.MinguoEra ROC;
+  }
+
+  public final class ThaiBuddhistChronology extends java.time.chrono.AbstractChronology implements java.io.Serializable {
+    method public java.time.chrono.ThaiBuddhistDate date(java.time.chrono.Era, int, int, int);
+    method public java.time.chrono.ThaiBuddhistDate date(int, int, int);
+    method public java.time.chrono.ThaiBuddhistDate date(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ThaiBuddhistDate dateEpochDay(long);
+    method public java.time.chrono.ThaiBuddhistDate dateNow();
+    method public java.time.chrono.ThaiBuddhistDate dateNow(java.time.ZoneId);
+    method public java.time.chrono.ThaiBuddhistDate dateNow(java.time.Clock);
+    method public java.time.chrono.ThaiBuddhistDate dateYearDay(java.time.chrono.Era, int, int);
+    method public java.time.chrono.ThaiBuddhistDate dateYearDay(int, int);
+    method public java.time.chrono.ThaiBuddhistEra eraOf(int);
+    method public java.util.List<java.time.chrono.Era> eras();
+    method public java.lang.String getCalendarType();
+    method public java.lang.String getId();
+    method public boolean isLeapYear(long);
+    method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.ThaiBuddhistDate> localDateTime(java.time.temporal.TemporalAccessor);
+    method public int prolepticYear(java.time.chrono.Era, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.ThaiBuddhistDate> zonedDateTime(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.ThaiBuddhistDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
+    field public static final java.time.chrono.ThaiBuddhistChronology INSTANCE;
+  }
+
+  public final class ThaiBuddhistDate extends java.time.chrono.ChronoLocalDateImpl implements java.time.chrono.ChronoLocalDate java.io.Serializable {
+    method public final java.time.chrono.ChronoLocalDateTime<java.time.chrono.ThaiBuddhistDate> atTime(java.time.LocalTime);
+    method public static java.time.chrono.ThaiBuddhistDate from(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ThaiBuddhistChronology getChronology();
+    method public java.time.chrono.ThaiBuddhistEra getEra();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int lengthOfMonth();
+    method public static java.time.chrono.ThaiBuddhistDate now();
+    method public static java.time.chrono.ThaiBuddhistDate now(java.time.ZoneId);
+    method public static java.time.chrono.ThaiBuddhistDate now(java.time.Clock);
+    method public static java.time.chrono.ThaiBuddhistDate of(int, int, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public long toEpochDay();
+    method public java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+  }
+
+  public final class ThaiBuddhistEra extends java.lang.Enum implements java.time.chrono.Era {
+    method public int getValue();
+    method public static java.time.chrono.ThaiBuddhistEra of(int);
+    method public static java.time.chrono.ThaiBuddhistEra valueOf(java.lang.String);
+    method public static final java.time.chrono.ThaiBuddhistEra[] values();
+    enum_constant public static final java.time.chrono.ThaiBuddhistEra BE;
+    enum_constant public static final java.time.chrono.ThaiBuddhistEra BEFORE_BE;
+  }
+
+}
+
+package java.time.format {
+
+  public final class DateTimeFormatter {
+    method public java.lang.String format(java.time.temporal.TemporalAccessor);
+    method public void formatTo(java.time.temporal.TemporalAccessor, java.lang.Appendable);
+    method public java.time.chrono.Chronology getChronology();
+    method public java.time.format.DecimalStyle getDecimalStyle();
+    method public java.util.Locale getLocale();
+    method public java.util.Set<java.time.temporal.TemporalField> getResolverFields();
+    method public java.time.format.ResolverStyle getResolverStyle();
+    method public java.time.ZoneId getZone();
+    method public static java.time.format.DateTimeFormatter ofLocalizedDate(java.time.format.FormatStyle);
+    method public static java.time.format.DateTimeFormatter ofLocalizedDateTime(java.time.format.FormatStyle);
+    method public static java.time.format.DateTimeFormatter ofLocalizedDateTime(java.time.format.FormatStyle, java.time.format.FormatStyle);
+    method public static java.time.format.DateTimeFormatter ofLocalizedTime(java.time.format.FormatStyle);
+    method public static java.time.format.DateTimeFormatter ofPattern(java.lang.String);
+    method public static java.time.format.DateTimeFormatter ofPattern(java.lang.String, java.util.Locale);
+    method public java.time.temporal.TemporalAccessor parse(java.lang.CharSequence);
+    method public java.time.temporal.TemporalAccessor parse(java.lang.CharSequence, java.text.ParsePosition);
+    method public <T> T parse(java.lang.CharSequence, java.time.temporal.TemporalQuery<T>);
+    method public java.time.temporal.TemporalAccessor parseBest(java.lang.CharSequence, java.time.temporal.TemporalQuery<?>...);
+    method public java.time.temporal.TemporalAccessor parseUnresolved(java.lang.CharSequence, java.text.ParsePosition);
+    method public static final java.time.temporal.TemporalQuery<java.time.Period> parsedExcessDays();
+    method public static final java.time.temporal.TemporalQuery<java.lang.Boolean> parsedLeapSecond();
+    method public java.text.Format toFormat();
+    method public java.text.Format toFormat(java.time.temporal.TemporalQuery<?>);
+    method public java.time.format.DateTimeFormatter withChronology(java.time.chrono.Chronology);
+    method public java.time.format.DateTimeFormatter withDecimalStyle(java.time.format.DecimalStyle);
+    method public java.time.format.DateTimeFormatter withLocale(java.util.Locale);
+    method public java.time.format.DateTimeFormatter withResolverFields(java.time.temporal.TemporalField...);
+    method public java.time.format.DateTimeFormatter withResolverFields(java.util.Set<java.time.temporal.TemporalField>);
+    method public java.time.format.DateTimeFormatter withResolverStyle(java.time.format.ResolverStyle);
+    method public java.time.format.DateTimeFormatter withZone(java.time.ZoneId);
+    field public static final java.time.format.DateTimeFormatter BASIC_ISO_DATE;
+    field public static final java.time.format.DateTimeFormatter ISO_DATE;
+    field public static final java.time.format.DateTimeFormatter ISO_DATE_TIME;
+    field public static final java.time.format.DateTimeFormatter ISO_INSTANT;
+    field public static final java.time.format.DateTimeFormatter ISO_LOCAL_DATE;
+    field public static final java.time.format.DateTimeFormatter ISO_LOCAL_DATE_TIME;
+    field public static final java.time.format.DateTimeFormatter ISO_LOCAL_TIME;
+    field public static final java.time.format.DateTimeFormatter ISO_OFFSET_DATE;
+    field public static final java.time.format.DateTimeFormatter ISO_OFFSET_DATE_TIME;
+    field public static final java.time.format.DateTimeFormatter ISO_OFFSET_TIME;
+    field public static final java.time.format.DateTimeFormatter ISO_ORDINAL_DATE;
+    field public static final java.time.format.DateTimeFormatter ISO_TIME;
+    field public static final java.time.format.DateTimeFormatter ISO_WEEK_DATE;
+    field public static final java.time.format.DateTimeFormatter ISO_ZONED_DATE_TIME;
+    field public static final java.time.format.DateTimeFormatter RFC_1123_DATE_TIME;
+  }
+
+  public final class DateTimeFormatterBuilder {
+    ctor public DateTimeFormatterBuilder();
+    method public java.time.format.DateTimeFormatterBuilder append(java.time.format.DateTimeFormatter);
+    method public java.time.format.DateTimeFormatterBuilder appendChronologyId();
+    method public java.time.format.DateTimeFormatterBuilder appendChronologyText(java.time.format.TextStyle);
+    method public java.time.format.DateTimeFormatterBuilder appendFraction(java.time.temporal.TemporalField, int, int, boolean);
+    method public java.time.format.DateTimeFormatterBuilder appendInstant();
+    method public java.time.format.DateTimeFormatterBuilder appendInstant(int);
+    method public java.time.format.DateTimeFormatterBuilder appendLiteral(char);
+    method public java.time.format.DateTimeFormatterBuilder appendLiteral(java.lang.String);
+    method public java.time.format.DateTimeFormatterBuilder appendLocalized(java.time.format.FormatStyle, java.time.format.FormatStyle);
+    method public java.time.format.DateTimeFormatterBuilder appendLocalizedOffset(java.time.format.TextStyle);
+    method public java.time.format.DateTimeFormatterBuilder appendOffset(java.lang.String, java.lang.String);
+    method public java.time.format.DateTimeFormatterBuilder appendOffsetId();
+    method public java.time.format.DateTimeFormatterBuilder appendOptional(java.time.format.DateTimeFormatter);
+    method public java.time.format.DateTimeFormatterBuilder appendPattern(java.lang.String);
+    method public java.time.format.DateTimeFormatterBuilder appendText(java.time.temporal.TemporalField);
+    method public java.time.format.DateTimeFormatterBuilder appendText(java.time.temporal.TemporalField, java.time.format.TextStyle);
+    method public java.time.format.DateTimeFormatterBuilder appendText(java.time.temporal.TemporalField, java.util.Map<java.lang.Long, java.lang.String>);
+    method public java.time.format.DateTimeFormatterBuilder appendValue(java.time.temporal.TemporalField);
+    method public java.time.format.DateTimeFormatterBuilder appendValue(java.time.temporal.TemporalField, int);
+    method public java.time.format.DateTimeFormatterBuilder appendValue(java.time.temporal.TemporalField, int, int, java.time.format.SignStyle);
+    method public java.time.format.DateTimeFormatterBuilder appendValueReduced(java.time.temporal.TemporalField, int, int, int);
+    method public java.time.format.DateTimeFormatterBuilder appendValueReduced(java.time.temporal.TemporalField, int, int, java.time.chrono.ChronoLocalDate);
+    method public java.time.format.DateTimeFormatterBuilder appendZoneId();
+    method public java.time.format.DateTimeFormatterBuilder appendZoneOrOffsetId();
+    method public java.time.format.DateTimeFormatterBuilder appendZoneRegionId();
+    method public java.time.format.DateTimeFormatterBuilder appendZoneText(java.time.format.TextStyle);
+    method public java.time.format.DateTimeFormatterBuilder appendZoneText(java.time.format.TextStyle, java.util.Set<java.time.ZoneId>);
+    method public static java.lang.String getLocalizedDateTimePattern(java.time.format.FormatStyle, java.time.format.FormatStyle, java.time.chrono.Chronology, java.util.Locale);
+    method public java.time.format.DateTimeFormatterBuilder optionalEnd();
+    method public java.time.format.DateTimeFormatterBuilder optionalStart();
+    method public java.time.format.DateTimeFormatterBuilder padNext(int);
+    method public java.time.format.DateTimeFormatterBuilder padNext(int, char);
+    method public java.time.format.DateTimeFormatterBuilder parseCaseInsensitive();
+    method public java.time.format.DateTimeFormatterBuilder parseCaseSensitive();
+    method public java.time.format.DateTimeFormatterBuilder parseDefaulting(java.time.temporal.TemporalField, long);
+    method public java.time.format.DateTimeFormatterBuilder parseLenient();
+    method public java.time.format.DateTimeFormatterBuilder parseStrict();
+    method public java.time.format.DateTimeFormatter toFormatter();
+    method public java.time.format.DateTimeFormatter toFormatter(java.util.Locale);
+  }
+
+  public class DateTimeParseException extends java.time.DateTimeException {
+    ctor public DateTimeParseException(java.lang.String, java.lang.CharSequence, int);
+    ctor public DateTimeParseException(java.lang.String, java.lang.CharSequence, int, java.lang.Throwable);
+    method public int getErrorIndex();
+    method public java.lang.String getParsedString();
+  }
+
+  public final class DecimalStyle {
+    method public static java.util.Set<java.util.Locale> getAvailableLocales();
+    method public char getDecimalSeparator();
+    method public char getNegativeSign();
+    method public char getPositiveSign();
+    method public char getZeroDigit();
+    method public static java.time.format.DecimalStyle of(java.util.Locale);
+    method public static java.time.format.DecimalStyle ofDefaultLocale();
+    method public java.time.format.DecimalStyle withDecimalSeparator(char);
+    method public java.time.format.DecimalStyle withNegativeSign(char);
+    method public java.time.format.DecimalStyle withPositiveSign(char);
+    method public java.time.format.DecimalStyle withZeroDigit(char);
+    field public static final java.time.format.DecimalStyle STANDARD;
+  }
+
+  public final class FormatStyle extends java.lang.Enum {
+    method public static java.time.format.FormatStyle valueOf(java.lang.String);
+    method public static final java.time.format.FormatStyle[] values();
+    enum_constant public static final java.time.format.FormatStyle FULL;
+    enum_constant public static final java.time.format.FormatStyle LONG;
+    enum_constant public static final java.time.format.FormatStyle MEDIUM;
+    enum_constant public static final java.time.format.FormatStyle SHORT;
+  }
+
+  public final class ResolverStyle extends java.lang.Enum {
+    method public static java.time.format.ResolverStyle valueOf(java.lang.String);
+    method public static final java.time.format.ResolverStyle[] values();
+    enum_constant public static final java.time.format.ResolverStyle LENIENT;
+    enum_constant public static final java.time.format.ResolverStyle SMART;
+    enum_constant public static final java.time.format.ResolverStyle STRICT;
+  }
+
+  public final class SignStyle extends java.lang.Enum {
+    method public static java.time.format.SignStyle valueOf(java.lang.String);
+    method public static final java.time.format.SignStyle[] values();
+    enum_constant public static final java.time.format.SignStyle ALWAYS;
+    enum_constant public static final java.time.format.SignStyle EXCEEDS_PAD;
+    enum_constant public static final java.time.format.SignStyle NEVER;
+    enum_constant public static final java.time.format.SignStyle NORMAL;
+    enum_constant public static final java.time.format.SignStyle NOT_NEGATIVE;
+  }
+
+  public final class TextStyle extends java.lang.Enum {
+    method public java.time.format.TextStyle asNormal();
+    method public java.time.format.TextStyle asStandalone();
+    method public boolean isStandalone();
+    method public static java.time.format.TextStyle valueOf(java.lang.String);
+    method public static final java.time.format.TextStyle[] values();
+    enum_constant public static final java.time.format.TextStyle FULL;
+    enum_constant public static final java.time.format.TextStyle FULL_STANDALONE;
+    enum_constant public static final java.time.format.TextStyle NARROW;
+    enum_constant public static final java.time.format.TextStyle NARROW_STANDALONE;
+    enum_constant public static final java.time.format.TextStyle SHORT;
+    enum_constant public static final java.time.format.TextStyle SHORT_STANDALONE;
+  }
+
+}
+
+package java.time.temporal {
+
+  public final class ChronoField extends java.lang.Enum implements java.time.temporal.TemporalField {
+    method public <R extends java.time.temporal.Temporal> R adjustInto(R, long);
+    method public int checkValidIntValue(long);
+    method public long checkValidValue(long);
+    method public java.time.temporal.TemporalUnit getBaseUnit();
+    method public java.lang.String getDisplayName(java.util.Locale);
+    method public long getFrom(java.time.temporal.TemporalAccessor);
+    method public java.time.temporal.TemporalUnit getRangeUnit();
+    method public boolean isDateBased();
+    method public boolean isSupportedBy(java.time.temporal.TemporalAccessor);
+    method public boolean isTimeBased();
+    method public java.time.temporal.ValueRange range();
+    method public java.time.temporal.ValueRange rangeRefinedBy(java.time.temporal.TemporalAccessor);
+    method public static java.time.temporal.ChronoField valueOf(java.lang.String);
+    method public static final java.time.temporal.ChronoField[] values();
+    enum_constant public static final java.time.temporal.ChronoField ALIGNED_DAY_OF_WEEK_IN_MONTH;
+    enum_constant public static final java.time.temporal.ChronoField ALIGNED_DAY_OF_WEEK_IN_YEAR;
+    enum_constant public static final java.time.temporal.ChronoField ALIGNED_WEEK_OF_MONTH;
+    enum_constant public static final java.time.temporal.ChronoField ALIGNED_WEEK_OF_YEAR;
+    enum_constant public static final java.time.temporal.ChronoField AMPM_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField CLOCK_HOUR_OF_AMPM;
+    enum_constant public static final java.time.temporal.ChronoField CLOCK_HOUR_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField DAY_OF_MONTH;
+    enum_constant public static final java.time.temporal.ChronoField DAY_OF_WEEK;
+    enum_constant public static final java.time.temporal.ChronoField DAY_OF_YEAR;
+    enum_constant public static final java.time.temporal.ChronoField EPOCH_DAY;
+    enum_constant public static final java.time.temporal.ChronoField ERA;
+    enum_constant public static final java.time.temporal.ChronoField HOUR_OF_AMPM;
+    enum_constant public static final java.time.temporal.ChronoField HOUR_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField INSTANT_SECONDS;
+    enum_constant public static final java.time.temporal.ChronoField MICRO_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField MICRO_OF_SECOND;
+    enum_constant public static final java.time.temporal.ChronoField MILLI_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField MILLI_OF_SECOND;
+    enum_constant public static final java.time.temporal.ChronoField MINUTE_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField MINUTE_OF_HOUR;
+    enum_constant public static final java.time.temporal.ChronoField MONTH_OF_YEAR;
+    enum_constant public static final java.time.temporal.ChronoField NANO_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField NANO_OF_SECOND;
+    enum_constant public static final java.time.temporal.ChronoField OFFSET_SECONDS;
+    enum_constant public static final java.time.temporal.ChronoField PROLEPTIC_MONTH;
+    enum_constant public static final java.time.temporal.ChronoField SECOND_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField SECOND_OF_MINUTE;
+    enum_constant public static final java.time.temporal.ChronoField YEAR;
+    enum_constant public static final java.time.temporal.ChronoField YEAR_OF_ERA;
+  }
+
+  public final class ChronoUnit extends java.lang.Enum implements java.time.temporal.TemporalUnit {
+    method public <R extends java.time.temporal.Temporal> R addTo(R, long);
+    method public long between(java.time.temporal.Temporal, java.time.temporal.Temporal);
+    method public java.time.Duration getDuration();
+    method public boolean isDateBased();
+    method public boolean isDurationEstimated();
+    method public boolean isSupportedBy(java.time.temporal.Temporal);
+    method public boolean isTimeBased();
+    method public static java.time.temporal.ChronoUnit valueOf(java.lang.String);
+    method public static final java.time.temporal.ChronoUnit[] values();
+    enum_constant public static final java.time.temporal.ChronoUnit CENTURIES;
+    enum_constant public static final java.time.temporal.ChronoUnit DAYS;
+    enum_constant public static final java.time.temporal.ChronoUnit DECADES;
+    enum_constant public static final java.time.temporal.ChronoUnit ERAS;
+    enum_constant public static final java.time.temporal.ChronoUnit FOREVER;
+    enum_constant public static final java.time.temporal.ChronoUnit HALF_DAYS;
+    enum_constant public static final java.time.temporal.ChronoUnit HOURS;
+    enum_constant public static final java.time.temporal.ChronoUnit MICROS;
+    enum_constant public static final java.time.temporal.ChronoUnit MILLENNIA;
+    enum_constant public static final java.time.temporal.ChronoUnit MILLIS;
+    enum_constant public static final java.time.temporal.ChronoUnit MINUTES;
+    enum_constant public static final java.time.temporal.ChronoUnit MONTHS;
+    enum_constant public static final java.time.temporal.ChronoUnit NANOS;
+    enum_constant public static final java.time.temporal.ChronoUnit SECONDS;
+    enum_constant public static final java.time.temporal.ChronoUnit WEEKS;
+    enum_constant public static final java.time.temporal.ChronoUnit YEARS;
+  }
+
+  public final class IsoFields {
+    field public static final java.time.temporal.TemporalField DAY_OF_QUARTER;
+    field public static final java.time.temporal.TemporalField QUARTER_OF_YEAR;
+    field public static final java.time.temporal.TemporalUnit QUARTER_YEARS;
+    field public static final java.time.temporal.TemporalField WEEK_BASED_YEAR;
+    field public static final java.time.temporal.TemporalUnit WEEK_BASED_YEARS;
+    field public static final java.time.temporal.TemporalField WEEK_OF_WEEK_BASED_YEAR;
+  }
+
+  public final class JulianFields {
+    field public static final java.time.temporal.TemporalField JULIAN_DAY;
+    field public static final java.time.temporal.TemporalField MODIFIED_JULIAN_DAY;
+    field public static final java.time.temporal.TemporalField RATA_DIE;
+  }
+
+  public abstract interface Temporal implements java.time.temporal.TemporalAccessor {
+    method public abstract boolean isSupported(java.time.temporal.TemporalUnit);
+    method public default java.time.temporal.Temporal minus(java.time.temporal.TemporalAmount);
+    method public default java.time.temporal.Temporal minus(long, java.time.temporal.TemporalUnit);
+    method public default java.time.temporal.Temporal plus(java.time.temporal.TemporalAmount);
+    method public abstract java.time.temporal.Temporal plus(long, java.time.temporal.TemporalUnit);
+    method public abstract long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public default java.time.temporal.Temporal with(java.time.temporal.TemporalAdjuster);
+    method public abstract java.time.temporal.Temporal with(java.time.temporal.TemporalField, long);
+  }
+
+  public abstract interface TemporalAccessor {
+    method public default int get(java.time.temporal.TemporalField);
+    method public abstract long getLong(java.time.temporal.TemporalField);
+    method public abstract boolean isSupported(java.time.temporal.TemporalField);
+    method public default <R> R query(java.time.temporal.TemporalQuery<R>);
+    method public default java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+  }
+
+  public abstract interface TemporalAdjuster {
+    method public abstract java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+  }
+
+  public final class TemporalAdjusters {
+    method public static java.time.temporal.TemporalAdjuster dayOfWeekInMonth(int, java.time.DayOfWeek);
+    method public static java.time.temporal.TemporalAdjuster firstDayOfMonth();
+    method public static java.time.temporal.TemporalAdjuster firstDayOfNextMonth();
+    method public static java.time.temporal.TemporalAdjuster firstDayOfNextYear();
+    method public static java.time.temporal.TemporalAdjuster firstDayOfYear();
+    method public static java.time.temporal.TemporalAdjuster firstInMonth(java.time.DayOfWeek);
+    method public static java.time.temporal.TemporalAdjuster lastDayOfMonth();
+    method public static java.time.temporal.TemporalAdjuster lastDayOfYear();
+    method public static java.time.temporal.TemporalAdjuster lastInMonth(java.time.DayOfWeek);
+    method public static java.time.temporal.TemporalAdjuster next(java.time.DayOfWeek);
+    method public static java.time.temporal.TemporalAdjuster nextOrSame(java.time.DayOfWeek);
+    method public static java.time.temporal.TemporalAdjuster ofDateAdjuster(java.util.function.UnaryOperator<java.time.LocalDate>);
+    method public static java.time.temporal.TemporalAdjuster previous(java.time.DayOfWeek);
+    method public static java.time.temporal.TemporalAdjuster previousOrSame(java.time.DayOfWeek);
+  }
+
+  public abstract interface TemporalAmount {
+    method public abstract java.time.temporal.Temporal addTo(java.time.temporal.Temporal);
+    method public abstract long get(java.time.temporal.TemporalUnit);
+    method public abstract java.util.List<java.time.temporal.TemporalUnit> getUnits();
+    method public abstract java.time.temporal.Temporal subtractFrom(java.time.temporal.Temporal);
+  }
+
+  public abstract interface TemporalField {
+    method public abstract <R extends java.time.temporal.Temporal> R adjustInto(R, long);
+    method public abstract java.time.temporal.TemporalUnit getBaseUnit();
+    method public default java.lang.String getDisplayName(java.util.Locale);
+    method public abstract long getFrom(java.time.temporal.TemporalAccessor);
+    method public abstract java.time.temporal.TemporalUnit getRangeUnit();
+    method public abstract boolean isDateBased();
+    method public abstract boolean isSupportedBy(java.time.temporal.TemporalAccessor);
+    method public abstract boolean isTimeBased();
+    method public abstract java.time.temporal.ValueRange range();
+    method public abstract java.time.temporal.ValueRange rangeRefinedBy(java.time.temporal.TemporalAccessor);
+    method public default java.time.temporal.TemporalAccessor resolve(java.util.Map<java.time.temporal.TemporalField, java.lang.Long>, java.time.temporal.TemporalAccessor, java.time.format.ResolverStyle);
+    method public abstract java.lang.String toString();
+  }
+
+  public final class TemporalQueries {
+    method public static java.time.temporal.TemporalQuery<java.time.chrono.Chronology> chronology();
+    method public static java.time.temporal.TemporalQuery<java.time.LocalDate> localDate();
+    method public static java.time.temporal.TemporalQuery<java.time.LocalTime> localTime();
+    method public static java.time.temporal.TemporalQuery<java.time.ZoneOffset> offset();
+    method public static java.time.temporal.TemporalQuery<java.time.temporal.TemporalUnit> precision();
+    method public static java.time.temporal.TemporalQuery<java.time.ZoneId> zone();
+    method public static java.time.temporal.TemporalQuery<java.time.ZoneId> zoneId();
+  }
+
+  public abstract interface TemporalQuery<R> {
+    method public abstract R queryFrom(java.time.temporal.TemporalAccessor);
+  }
+
+  public abstract interface TemporalUnit {
+    method public abstract <R extends java.time.temporal.Temporal> R addTo(R, long);
+    method public abstract long between(java.time.temporal.Temporal, java.time.temporal.Temporal);
+    method public abstract java.time.Duration getDuration();
+    method public abstract boolean isDateBased();
+    method public abstract boolean isDurationEstimated();
+    method public default boolean isSupportedBy(java.time.temporal.Temporal);
+    method public abstract boolean isTimeBased();
+    method public abstract java.lang.String toString();
+  }
+
+  public class UnsupportedTemporalTypeException extends java.time.DateTimeException {
+    ctor public UnsupportedTemporalTypeException(java.lang.String);
+    ctor public UnsupportedTemporalTypeException(java.lang.String, java.lang.Throwable);
+  }
+
+  public final class ValueRange implements java.io.Serializable {
+    method public int checkValidIntValue(long, java.time.temporal.TemporalField);
+    method public long checkValidValue(long, java.time.temporal.TemporalField);
+    method public long getLargestMinimum();
+    method public long getMaximum();
+    method public long getMinimum();
+    method public long getSmallestMaximum();
+    method public boolean isFixed();
+    method public boolean isIntValue();
+    method public boolean isValidIntValue(long);
+    method public boolean isValidValue(long);
+    method public static java.time.temporal.ValueRange of(long, long);
+    method public static java.time.temporal.ValueRange of(long, long, long);
+    method public static java.time.temporal.ValueRange of(long, long, long, long);
+  }
+
+  public final class WeekFields implements java.io.Serializable {
+    method public java.time.temporal.TemporalField dayOfWeek();
+    method public java.time.DayOfWeek getFirstDayOfWeek();
+    method public int getMinimalDaysInFirstWeek();
+    method public static java.time.temporal.WeekFields of(java.util.Locale);
+    method public static java.time.temporal.WeekFields of(java.time.DayOfWeek, int);
+    method public java.time.temporal.TemporalField weekBasedYear();
+    method public java.time.temporal.TemporalField weekOfMonth();
+    method public java.time.temporal.TemporalField weekOfWeekBasedYear();
+    method public java.time.temporal.TemporalField weekOfYear();
+    field public static final java.time.temporal.WeekFields ISO;
+    field public static final java.time.temporal.WeekFields SUNDAY_START;
+    field public static final java.time.temporal.TemporalUnit WEEK_BASED_YEARS;
+  }
+
+}
+
+package java.time.zone {
+
+  public final class ZoneOffsetTransition implements java.lang.Comparable java.io.Serializable {
+    method public int compareTo(java.time.zone.ZoneOffsetTransition);
+    method public java.time.LocalDateTime getDateTimeAfter();
+    method public java.time.LocalDateTime getDateTimeBefore();
+    method public java.time.Duration getDuration();
+    method public java.time.Instant getInstant();
+    method public java.time.ZoneOffset getOffsetAfter();
+    method public java.time.ZoneOffset getOffsetBefore();
+    method public boolean isGap();
+    method public boolean isOverlap();
+    method public boolean isValidOffset(java.time.ZoneOffset);
+    method public static java.time.zone.ZoneOffsetTransition of(java.time.LocalDateTime, java.time.ZoneOffset, java.time.ZoneOffset);
+    method public long toEpochSecond();
+  }
+
+  public final class ZoneOffsetTransitionRule implements java.io.Serializable {
+    method public java.time.zone.ZoneOffsetTransition createTransition(int);
+    method public int getDayOfMonthIndicator();
+    method public java.time.DayOfWeek getDayOfWeek();
+    method public java.time.LocalTime getLocalTime();
+    method public java.time.Month getMonth();
+    method public java.time.ZoneOffset getOffsetAfter();
+    method public java.time.ZoneOffset getOffsetBefore();
+    method public java.time.ZoneOffset getStandardOffset();
+    method public java.time.zone.ZoneOffsetTransitionRule.TimeDefinition getTimeDefinition();
+    method public boolean isMidnightEndOfDay();
+    method public static java.time.zone.ZoneOffsetTransitionRule of(java.time.Month, int, java.time.DayOfWeek, java.time.LocalTime, boolean, java.time.zone.ZoneOffsetTransitionRule.TimeDefinition, java.time.ZoneOffset, java.time.ZoneOffset, java.time.ZoneOffset);
+  }
+
+  public static final class ZoneOffsetTransitionRule.TimeDefinition extends java.lang.Enum {
+    method public java.time.LocalDateTime createDateTime(java.time.LocalDateTime, java.time.ZoneOffset, java.time.ZoneOffset);
+    method public static java.time.zone.ZoneOffsetTransitionRule.TimeDefinition valueOf(java.lang.String);
+    method public static final java.time.zone.ZoneOffsetTransitionRule.TimeDefinition[] values();
+    enum_constant public static final java.time.zone.ZoneOffsetTransitionRule.TimeDefinition STANDARD;
+    enum_constant public static final java.time.zone.ZoneOffsetTransitionRule.TimeDefinition UTC;
+    enum_constant public static final java.time.zone.ZoneOffsetTransitionRule.TimeDefinition WALL;
+  }
+
+  public final class ZoneRules implements java.io.Serializable {
+    method public java.time.Duration getDaylightSavings(java.time.Instant);
+    method public java.time.ZoneOffset getOffset(java.time.Instant);
+    method public java.time.ZoneOffset getOffset(java.time.LocalDateTime);
+    method public java.time.ZoneOffset getStandardOffset(java.time.Instant);
+    method public java.time.zone.ZoneOffsetTransition getTransition(java.time.LocalDateTime);
+    method public java.util.List<java.time.zone.ZoneOffsetTransitionRule> getTransitionRules();
+    method public java.util.List<java.time.zone.ZoneOffsetTransition> getTransitions();
+    method public java.util.List<java.time.ZoneOffset> getValidOffsets(java.time.LocalDateTime);
+    method public boolean isDaylightSavings(java.time.Instant);
+    method public boolean isFixedOffset();
+    method public boolean isValidOffset(java.time.LocalDateTime, java.time.ZoneOffset);
+    method public java.time.zone.ZoneOffsetTransition nextTransition(java.time.Instant);
+    method public static java.time.zone.ZoneRules of(java.time.ZoneOffset, java.time.ZoneOffset, java.util.List<java.time.zone.ZoneOffsetTransition>, java.util.List<java.time.zone.ZoneOffsetTransition>, java.util.List<java.time.zone.ZoneOffsetTransitionRule>);
+    method public static java.time.zone.ZoneRules of(java.time.ZoneOffset);
+    method public java.time.zone.ZoneOffsetTransition previousTransition(java.time.Instant);
+  }
+
+  public class ZoneRulesException extends java.time.DateTimeException {
+    ctor public ZoneRulesException(java.lang.String);
+    ctor public ZoneRulesException(java.lang.String, java.lang.Throwable);
+  }
+
+}
+
 package java.util {
 
   public abstract class AbstractCollection<E> implements java.util.Collection {
@@ -58704,7 +60334,9 @@
     method public int get(int);
     method public int getActualMaximum(int);
     method public int getActualMinimum(int);
+    method public static java.util.Set<java.lang.String> getAvailableCalendarTypes();
     method public static synchronized java.util.Locale[] getAvailableLocales();
+    method public java.lang.String getCalendarType();
     method public java.lang.String getDisplayName(int, int, java.util.Locale);
     method public java.util.Map<java.lang.String, java.lang.Integer> getDisplayNames(int, int, java.util.Locale);
     method public int getFirstDayOfWeek();
@@ -58739,6 +60371,7 @@
     method public void setTimeInMillis(long);
     method public void setTimeZone(java.util.TimeZone);
     method public void setWeekDate(int, int, int);
+    method public final java.time.Instant toInstant();
     field public static final int ALL_STYLES = 0; // 0x0
     field public static final int AM = 0; // 0x0
     field public static final int AM_PM = 9; // 0x9
@@ -58761,12 +60394,16 @@
     field public static final int JULY = 6; // 0x6
     field public static final int JUNE = 5; // 0x5
     field public static final int LONG = 2; // 0x2
+    field public static final int LONG_FORMAT = 2; // 0x2
+    field public static final int LONG_STANDALONE = 32770; // 0x8002
     field public static final int MARCH = 2; // 0x2
     field public static final int MAY = 4; // 0x4
     field public static final int MILLISECOND = 14; // 0xe
     field public static final int MINUTE = 12; // 0xc
     field public static final int MONDAY = 2; // 0x2
     field public static final int MONTH = 2; // 0x2
+    field public static final int NARROW_FORMAT = 4; // 0x4
+    field public static final int NARROW_STANDALONE = 32772; // 0x8004
     field public static final int NOVEMBER = 10; // 0xa
     field public static final int OCTOBER = 9; // 0x9
     field public static final int PM = 1; // 0x1
@@ -58774,6 +60411,8 @@
     field public static final int SECOND = 13; // 0xd
     field public static final int SEPTEMBER = 8; // 0x8
     field public static final int SHORT = 1; // 0x1
+    field public static final int SHORT_FORMAT = 1; // 0x1
+    field public static final int SHORT_STANDALONE = 32769; // 0x8001
     field public static final int SUNDAY = 1; // 0x1
     field public static final int THURSDAY = 5; // 0x5
     field public static final int TUESDAY = 3; // 0x3
@@ -58790,6 +60429,24 @@
     field protected long time;
   }
 
+  public static class Calendar.Builder {
+    ctor public Calendar.Builder();
+    method public java.util.Calendar build();
+    method public java.util.Calendar.Builder set(int, int);
+    method public java.util.Calendar.Builder setCalendarType(java.lang.String);
+    method public java.util.Calendar.Builder setDate(int, int, int);
+    method public java.util.Calendar.Builder setFields(int...);
+    method public java.util.Calendar.Builder setInstant(long);
+    method public java.util.Calendar.Builder setInstant(java.util.Date);
+    method public java.util.Calendar.Builder setLenient(boolean);
+    method public java.util.Calendar.Builder setLocale(java.util.Locale);
+    method public java.util.Calendar.Builder setTimeOfDay(int, int, int);
+    method public java.util.Calendar.Builder setTimeOfDay(int, int, int, int);
+    method public java.util.Calendar.Builder setTimeZone(java.util.TimeZone);
+    method public java.util.Calendar.Builder setWeekDate(int, int, int);
+    method public java.util.Calendar.Builder setWeekDefinition(int, int);
+  }
+
   public abstract interface Collection<E> implements java.lang.Iterable {
     method public abstract boolean add(E);
     method public abstract boolean addAll(java.util.Collection<? extends E>);
@@ -58925,6 +60582,7 @@
     method public boolean before(java.util.Date);
     method public java.lang.Object clone();
     method public int compareTo(java.util.Date);
+    method public static java.util.Date from(java.time.Instant);
     method public deprecated int getDate();
     method public deprecated int getDay();
     method public deprecated int getHours();
@@ -58943,6 +60601,7 @@
     method public void setTime(long);
     method public deprecated void setYear(int);
     method public deprecated java.lang.String toGMTString();
+    method public java.time.Instant toInstant();
     method public deprecated java.lang.String toLocaleString();
   }
 
@@ -59112,6 +60771,7 @@
     method public void add(int, int);
     method protected void computeFields();
     method protected void computeTime();
+    method public static java.util.GregorianCalendar from(java.time.ZonedDateTime);
     method public int getGreatestMinimum(int);
     method public final java.util.Date getGregorianChange();
     method public int getLeastMaximum(int);
@@ -59121,6 +60781,7 @@
     method public final boolean isWeekDateSupported();
     method public void roll(int, boolean);
     method public void setGregorianChange(java.util.Date);
+    method public java.time.ZonedDateTime toZonedDateTime();
     field public static final int AD = 1; // 0x1
     field public static final int BC = 0; // 0x0
   }
@@ -60148,12 +61809,14 @@
     method public int getOffset(long);
     method public abstract int getRawOffset();
     method public static synchronized java.util.TimeZone getTimeZone(java.lang.String);
+    method public static java.util.TimeZone getTimeZone(java.time.ZoneId);
     method public boolean hasSameRules(java.util.TimeZone);
     method public abstract boolean inDaylightTime(java.util.Date);
     method public boolean observesDaylightTime();
     method public static synchronized void setDefault(java.util.TimeZone);
     method public void setID(java.lang.String);
     method public abstract void setRawOffset(int);
+    method public java.time.ZoneId toZoneId();
     method public abstract boolean useDaylightTime();
     field public static final int LONG = 1; // 0x1
     field public static final int SHORT = 0; // 0x0
@@ -60760,31 +62423,31 @@
     ctor public CopyOnWriteArrayList();
     ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
     ctor public CopyOnWriteArrayList(E[]);
-    method public synchronized boolean add(E);
-    method public synchronized void add(int, E);
-    method public synchronized boolean addAll(java.util.Collection<? extends E>);
-    method public synchronized boolean addAll(int, java.util.Collection<? extends E>);
-    method public synchronized int addAllAbsent(java.util.Collection<? extends E>);
-    method public synchronized boolean addIfAbsent(E);
-    method public synchronized void clear();
+    method public boolean add(E);
+    method public void add(int, E);
+    method public boolean addAll(java.util.Collection<? extends E>);
+    method public boolean addAll(int, java.util.Collection<? extends E>);
+    method public int addAllAbsent(java.util.Collection<? extends E>);
+    method public boolean addIfAbsent(E);
+    method public void clear();
     method public java.lang.Object clone();
     method public boolean contains(java.lang.Object);
     method public boolean containsAll(java.util.Collection<?>);
     method public void forEach(java.util.function.Consumer<? super E>);
     method public E get(int);
-    method public int indexOf(E, int);
     method public int indexOf(java.lang.Object);
+    method public int indexOf(E, int);
     method public boolean isEmpty();
     method public java.util.Iterator<E> iterator();
-    method public int lastIndexOf(E, int);
     method public int lastIndexOf(java.lang.Object);
-    method public java.util.ListIterator<E> listIterator(int);
+    method public int lastIndexOf(E, int);
     method public java.util.ListIterator<E> listIterator();
-    method public synchronized E remove(int);
-    method public synchronized boolean remove(java.lang.Object);
-    method public synchronized boolean removeAll(java.util.Collection<?>);
-    method public synchronized boolean retainAll(java.util.Collection<?>);
-    method public synchronized E set(int, E);
+    method public java.util.ListIterator<E> listIterator(int);
+    method public E remove(int);
+    method public boolean remove(java.lang.Object);
+    method public boolean removeAll(java.util.Collection<?>);
+    method public boolean retainAll(java.util.Collection<?>);
+    method public E set(int, E);
     method public int size();
     method public java.util.List<E> subList(int, int);
     method public java.lang.Object[] toArray();
@@ -62635,10 +64298,12 @@
     method public java.lang.StringBuffer appendTail(java.lang.StringBuffer);
     method public int end();
     method public int end(int);
+    method public int end(java.lang.String);
     method public boolean find();
     method public boolean find(int);
     method public java.lang.String group();
     method public java.lang.String group(int);
+    method public java.lang.String group(java.lang.String);
     method public int groupCount();
     method public boolean hasAnchoringBounds();
     method public boolean hasTransparentBounds();
@@ -62657,6 +64322,7 @@
     method public java.util.regex.Matcher reset(java.lang.CharSequence);
     method public int start();
     method public int start(int) throws java.lang.IllegalStateException;
+    method public int start(java.lang.String);
     method public java.util.regex.MatchResult toMatchResult();
     method public java.util.regex.Matcher useAnchoringBounds(boolean);
     method public java.util.regex.Matcher usePattern(java.util.regex.Pattern);
diff --git a/api/system-current.txt b/api/system-current.txt
index 2e32179..49dc7c5 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -40,6 +40,7 @@
     field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
     field public static final java.lang.String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET";
     field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
+    field public static final java.lang.String BIND_NETWORK_RECOMMENDATION_SERVICE = "android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE";
     field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
     field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
     field public static final java.lang.String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE";
@@ -62,7 +63,7 @@
     field public static final java.lang.String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
     field public static final java.lang.String BODY_SENSORS = "android.permission.BODY_SENSORS";
     field public static final java.lang.String BRICK = "android.permission.BRICK";
-    field public static final java.lang.String BROADCAST_NETWORK_PRIVILEGED = "android.permission.BROADCAST_NETWORK_PRIVILEGED";
+    field public static final deprecated java.lang.String BROADCAST_NETWORK_PRIVILEGED = "android.permission.BROADCAST_NETWORK_PRIVILEGED";
     field public static final java.lang.String BROADCAST_PACKAGE_REMOVED = "android.permission.BROADCAST_PACKAGE_REMOVED";
     field public static final java.lang.String BROADCAST_SMS = "android.permission.BROADCAST_SMS";
     field public static final java.lang.String BROADCAST_STICKY = "android.permission.BROADCAST_STICKY";
@@ -196,6 +197,7 @@
     field public static final java.lang.String REORDER_TASKS = "android.permission.REORDER_TASKS";
     field public static final java.lang.String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
     field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
+    field public static final java.lang.String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES";
     field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
     field public static final java.lang.String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
     field public static final java.lang.String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
@@ -8559,6 +8561,7 @@
     field public static final java.lang.String USER_SERVICE = "user";
     field public static final java.lang.String VIBRATOR_SERVICE = "vibrator";
     field public static final java.lang.String WALLPAPER_SERVICE = "wallpaper";
+    field public static final java.lang.String WIFI_AWARE_SERVICE = "wifiaware";
     field public static final java.lang.String WIFI_P2P_SERVICE = "wifip2p";
     field public static final java.lang.String WIFI_RTT_SERVICE = "rttmanager";
     field public static final java.lang.String WIFI_SCANNING_SERVICE = "wifiscanner";
@@ -10266,6 +10269,7 @@
     field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
     field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
     field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
+    field public static final java.lang.String FEATURE_WIFI_AWARE = "android.hardware.wifi.aware";
     field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
     field public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT = 32; // 0x20
     field public static final int FLAG_PERMISSION_POLICY_FIXED = 4; // 0x4
@@ -25604,6 +25608,7 @@
     field public static final int TRANSPORT_ETHERNET = 3; // 0x3
     field public static final int TRANSPORT_VPN = 4; // 0x4
     field public static final int TRANSPORT_WIFI = 1; // 0x1
+    field public static final int TRANSPORT_WIFI_AWARE = 5; // 0x5
   }
 
   public class NetworkInfo implements android.os.Parcelable {
@@ -25760,6 +25765,14 @@
     field public static final android.os.Parcelable.Creator<android.net.RecommendationRequest> CREATOR;
   }
 
+  public static final class RecommendationRequest.Builder {
+    ctor public RecommendationRequest.Builder();
+    method public android.net.RecommendationRequest build();
+    method public android.net.RecommendationRequest.Builder setCurrentRecommendedWifiConfig(android.net.wifi.WifiConfiguration);
+    method public android.net.RecommendationRequest.Builder setNetworkCapabilities(android.net.NetworkCapabilities);
+    method public android.net.RecommendationRequest.Builder setScanResults(android.net.wifi.ScanResult[]);
+  }
+
   public final class RecommendationResult implements android.os.Parcelable {
     method public static android.net.RecommendationResult createConnectRecommendation(android.net.wifi.WifiConfiguration);
     method public static android.net.RecommendationResult createDoNotConnectRecommendation();
@@ -25824,10 +25837,16 @@
     ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve);
     ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve, boolean);
     ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve, boolean, android.os.Bundle);
+    method public int calculateBadge(int);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final java.lang.String ATTRIBUTES_KEY_BADGING_CURVE = "android.net.attributes.key.BADGING_CURVE";
     field public static final java.lang.String ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL = "android.net.attributes.key.HAS_CAPTIVE_PORTAL";
     field public static final java.lang.String ATTRIBUTES_KEY_RANKING_SCORE_OFFSET = "android.net.attributes.key.RANKING_SCORE_OFFSET";
+    field public static final int BADGING_4K = 30; // 0x1e
+    field public static final int BADGING_HD = 20; // 0x14
+    field public static final int BADGING_NONE = 0; // 0x0
+    field public static final int BADGING_SD = 10; // 0xa
     field public static final android.os.Parcelable.Creator<android.net.ScoredNetwork> CREATOR;
     field public final android.os.Bundle attributes;
     field public final boolean meteredHint;
@@ -25835,6 +25854,9 @@
     field public final android.net.RssiCurve rssiCurve;
   }
 
+  public static abstract class ScoredNetwork.Badging implements java.lang.annotation.Annotation {
+  }
+
   public class TrafficStats {
     ctor public TrafficStats();
     method public static void clearThreadStatsTag();
@@ -26843,6 +26865,8 @@
   public class WifiConfiguration implements android.os.Parcelable {
     ctor public WifiConfiguration();
     method public int describeContents();
+    method public boolean hasNoInternetAccess();
+    method public boolean isNoInternetAccessExpected();
     method public boolean isPasspoint();
     method public void writeToParcel(android.os.Parcel, int);
     field public java.lang.String BSSID;
@@ -27015,6 +27039,7 @@
     method public static int calculateSignalLevel(int, int);
     method public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
     method public static int compareSignalLevel(int, int);
+    method public void connect(android.net.wifi.WifiConfiguration, android.net.wifi.WifiManager.ActionListener);
     method public android.net.wifi.WifiManager.MulticastLock createMulticastLock(java.lang.String);
     method public android.net.wifi.WifiManager.WifiLock createWifiLock(int, java.lang.String);
     method public android.net.wifi.WifiManager.WifiLock createWifiLock(java.lang.String);
@@ -27114,6 +27139,11 @@
     field public static final int WPS_WEP_PROHIBITED = 4; // 0x4
   }
 
+  public static abstract interface WifiManager.ActionListener {
+    method public abstract void onFailure(int);
+    method public abstract void onSuccess();
+  }
+
   public class WifiManager.MulticastLock {
     method public void acquire();
     method public boolean isHeld();
@@ -27294,6 +27324,122 @@
 
 }
 
+package android.net.wifi.aware {
+
+  public class AttachCallback {
+    ctor public AttachCallback();
+    method public void onAttachFailed();
+    method public void onAttached(android.net.wifi.aware.WifiAwareSession);
+  }
+
+  public final class Characteristics implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getMaxMatchFilterLength();
+    method public int getMaxServiceNameLength();
+    method public int getMaxServiceSpecificInfoLength();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.aware.Characteristics> CREATOR;
+  }
+
+  public class DiscoverySession {
+    method public java.lang.String createNetworkSpecifier(android.net.wifi.aware.PeerHandle, byte[]);
+    method public void destroy();
+    method public static int getMaxSendRetryCount();
+    method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[], int);
+    method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
+  }
+
+  public class DiscoverySessionCallback {
+    ctor public DiscoverySessionCallback();
+    method public void onMessageReceived(android.net.wifi.aware.PeerHandle, byte[]);
+    method public void onMessageSendFailed(int);
+    method public void onMessageSendSucceeded(int);
+    method public void onPublishStarted(android.net.wifi.aware.PublishDiscoverySession);
+    method public void onServiceDiscovered(android.net.wifi.aware.PeerHandle, byte[], java.util.List<byte[]>);
+    method public void onSessionConfigFailed();
+    method public void onSessionConfigUpdated();
+    method public void onSessionTerminated();
+    method public void onSubscribeStarted(android.net.wifi.aware.SubscribeDiscoverySession);
+  }
+
+  public class IdentityChangedListener {
+    ctor public IdentityChangedListener();
+    method public void onIdentityChanged(byte[]);
+  }
+
+  public class PeerHandle {
+  }
+
+  public final class PublishConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.aware.PublishConfig> CREATOR;
+    field public static final int PUBLISH_TYPE_SOLICITED = 1; // 0x1
+    field public static final int PUBLISH_TYPE_UNSOLICITED = 0; // 0x0
+  }
+
+  public static final class PublishConfig.Builder {
+    ctor public PublishConfig.Builder();
+    method public android.net.wifi.aware.PublishConfig build();
+    method public android.net.wifi.aware.PublishConfig.Builder setMatchFilter(java.util.List<byte[]>);
+    method public android.net.wifi.aware.PublishConfig.Builder setPublishCount(int);
+    method public android.net.wifi.aware.PublishConfig.Builder setPublishType(int);
+    method public android.net.wifi.aware.PublishConfig.Builder setServiceName(java.lang.String);
+    method public android.net.wifi.aware.PublishConfig.Builder setServiceSpecificInfo(byte[]);
+    method public android.net.wifi.aware.PublishConfig.Builder setTerminateNotificationEnabled(boolean);
+    method public android.net.wifi.aware.PublishConfig.Builder setTtlSec(int);
+  }
+
+  public class PublishDiscoverySession extends android.net.wifi.aware.DiscoverySession {
+    method public void updatePublish(android.net.wifi.aware.PublishConfig);
+  }
+
+  public final class SubscribeConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.aware.SubscribeConfig> CREATOR;
+    field public static final int MATCH_STYLE_ALL = 1; // 0x1
+    field public static final int MATCH_STYLE_FIRST_ONLY = 0; // 0x0
+    field public static final int SUBSCRIBE_TYPE_ACTIVE = 1; // 0x1
+    field public static final int SUBSCRIBE_TYPE_PASSIVE = 0; // 0x0
+  }
+
+  public static final class SubscribeConfig.Builder {
+    ctor public SubscribeConfig.Builder();
+    method public android.net.wifi.aware.SubscribeConfig build();
+    method public android.net.wifi.aware.SubscribeConfig.Builder setMatchFilter(java.util.List<byte[]>);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setMatchStyle(int);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setServiceName(java.lang.String);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setServiceSpecificInfo(byte[]);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setSubscribeCount(int);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setSubscribeType(int);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setTerminateNotificationEnabled(boolean);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setTtlSec(int);
+  }
+
+  public class SubscribeDiscoverySession extends android.net.wifi.aware.DiscoverySession {
+    method public void updateSubscribe(android.net.wifi.aware.SubscribeConfig);
+  }
+
+  public class WifiAwareManager {
+    method public void attach(android.net.wifi.aware.AttachCallback, android.os.Handler);
+    method public void attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler);
+    method public android.net.wifi.aware.Characteristics getCharacteristics();
+    method public boolean isAvailable();
+    field public static final java.lang.String ACTION_WIFI_AWARE_STATE_CHANGED = "android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED";
+    field public static final int WIFI_AWARE_DATA_PATH_ROLE_INITIATOR = 0; // 0x0
+    field public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1; // 0x1
+  }
+
+  public class WifiAwareSession {
+    method public java.lang.String createNetworkSpecifier(int, byte[], byte[]);
+    method public void destroy();
+    method public void publish(android.net.wifi.aware.PublishConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler);
+    method public void subscribe(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler);
+  }
+
+}
+
 package android.net.wifi.p2p {
 
   public class WifiP2pConfig implements android.os.Parcelable {
@@ -40626,6 +40772,8 @@
     method public java.lang.String getDeviceSoftwareVersion();
     method public java.lang.String getGroupIdLevel1();
     method public java.lang.String getIccAuthentication(int, int, java.lang.String);
+    method public java.lang.String getImei();
+    method public java.lang.String getImei(int);
     method public java.lang.String getLine1Number();
     method public java.lang.String getMmsUAProfUrl();
     method public java.lang.String getMmsUserAgent();
@@ -58374,8 +58522,10 @@
   public final class FileTime implements java.lang.Comparable {
     method public int compareTo(java.nio.file.attribute.FileTime);
     method public static java.nio.file.attribute.FileTime from(long, java.util.concurrent.TimeUnit);
+    method public static java.nio.file.attribute.FileTime from(java.time.Instant);
     method public static java.nio.file.attribute.FileTime fromMillis(long);
     method public long to(java.util.concurrent.TimeUnit);
+    method public java.time.Instant toInstant();
     method public long toMillis();
   }
 
@@ -61905,6 +62055,1515 @@
 
 }
 
+package java.time {
+
+  public abstract class Clock {
+    ctor protected Clock();
+    method public static java.time.Clock fixed(java.time.Instant, java.time.ZoneId);
+    method public abstract java.time.ZoneId getZone();
+    method public abstract java.time.Instant instant();
+    method public long millis();
+    method public static java.time.Clock offset(java.time.Clock, java.time.Duration);
+    method public static java.time.Clock system(java.time.ZoneId);
+    method public static java.time.Clock systemDefaultZone();
+    method public static java.time.Clock systemUTC();
+    method public static java.time.Clock tick(java.time.Clock, java.time.Duration);
+    method public static java.time.Clock tickMinutes(java.time.ZoneId);
+    method public static java.time.Clock tickSeconds(java.time.ZoneId);
+    method public abstract java.time.Clock withZone(java.time.ZoneId);
+  }
+
+  public class DateTimeException extends java.lang.RuntimeException {
+    ctor public DateTimeException(java.lang.String);
+    ctor public DateTimeException(java.lang.String, java.lang.Throwable);
+  }
+
+  public final class DayOfWeek extends java.lang.Enum implements java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public static java.time.DayOfWeek from(java.time.temporal.TemporalAccessor);
+    method public int get(java.time.temporal.TemporalField);
+    method public java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getValue();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public java.time.DayOfWeek minus(long);
+    method public static java.time.DayOfWeek of(int);
+    method public java.time.DayOfWeek plus(long);
+    method public <R> R query(java.time.temporal.TemporalQuery<R>);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public static java.time.DayOfWeek valueOf(java.lang.String);
+    method public static final java.time.DayOfWeek[] values();
+    enum_constant public static final java.time.DayOfWeek FRIDAY;
+    enum_constant public static final java.time.DayOfWeek MONDAY;
+    enum_constant public static final java.time.DayOfWeek SATURDAY;
+    enum_constant public static final java.time.DayOfWeek SUNDAY;
+    enum_constant public static final java.time.DayOfWeek THURSDAY;
+    enum_constant public static final java.time.DayOfWeek TUESDAY;
+    enum_constant public static final java.time.DayOfWeek WEDNESDAY;
+  }
+
+  public final class Duration implements java.lang.Comparable java.io.Serializable java.time.temporal.TemporalAmount {
+    method public java.time.Duration abs();
+    method public java.time.temporal.Temporal addTo(java.time.temporal.Temporal);
+    method public static java.time.Duration between(java.time.temporal.Temporal, java.time.temporal.Temporal);
+    method public int compareTo(java.time.Duration);
+    method public java.time.Duration dividedBy(long);
+    method public static java.time.Duration from(java.time.temporal.TemporalAmount);
+    method public long get(java.time.temporal.TemporalUnit);
+    method public int getNano();
+    method public long getSeconds();
+    method public java.util.List<java.time.temporal.TemporalUnit> getUnits();
+    method public boolean isNegative();
+    method public boolean isZero();
+    method public java.time.Duration minus(java.time.Duration);
+    method public java.time.Duration minus(long, java.time.temporal.TemporalUnit);
+    method public java.time.Duration minusDays(long);
+    method public java.time.Duration minusHours(long);
+    method public java.time.Duration minusMillis(long);
+    method public java.time.Duration minusMinutes(long);
+    method public java.time.Duration minusNanos(long);
+    method public java.time.Duration minusSeconds(long);
+    method public java.time.Duration multipliedBy(long);
+    method public java.time.Duration negated();
+    method public static java.time.Duration of(long, java.time.temporal.TemporalUnit);
+    method public static java.time.Duration ofDays(long);
+    method public static java.time.Duration ofHours(long);
+    method public static java.time.Duration ofMillis(long);
+    method public static java.time.Duration ofMinutes(long);
+    method public static java.time.Duration ofNanos(long);
+    method public static java.time.Duration ofSeconds(long);
+    method public static java.time.Duration ofSeconds(long, long);
+    method public static java.time.Duration parse(java.lang.CharSequence);
+    method public java.time.Duration plus(java.time.Duration);
+    method public java.time.Duration plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.Duration plusDays(long);
+    method public java.time.Duration plusHours(long);
+    method public java.time.Duration plusMillis(long);
+    method public java.time.Duration plusMinutes(long);
+    method public java.time.Duration plusNanos(long);
+    method public java.time.Duration plusSeconds(long);
+    method public java.time.temporal.Temporal subtractFrom(java.time.temporal.Temporal);
+    method public long toDays();
+    method public long toHours();
+    method public long toMillis();
+    method public long toMinutes();
+    method public long toNanos();
+    method public java.time.Duration withNanos(int);
+    method public java.time.Duration withSeconds(long);
+    field public static final java.time.Duration ZERO;
+  }
+
+  public final class Instant implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.OffsetDateTime atOffset(java.time.ZoneOffset);
+    method public java.time.ZonedDateTime atZone(java.time.ZoneId);
+    method public int compareTo(java.time.Instant);
+    method public static java.time.Instant from(java.time.temporal.TemporalAccessor);
+    method public long getEpochSecond();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getNano();
+    method public boolean isAfter(java.time.Instant);
+    method public boolean isBefore(java.time.Instant);
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
+    method public java.time.Instant minusMillis(long);
+    method public java.time.Instant minusNanos(long);
+    method public java.time.Instant minusSeconds(long);
+    method public static java.time.Instant now();
+    method public static java.time.Instant now(java.time.Clock);
+    method public static java.time.Instant ofEpochMilli(long);
+    method public static java.time.Instant ofEpochSecond(long);
+    method public static java.time.Instant ofEpochSecond(long, long);
+    method public static java.time.Instant parse(java.lang.CharSequence);
+    method public java.time.Instant plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.Instant plusMillis(long);
+    method public java.time.Instant plusNanos(long);
+    method public java.time.Instant plusSeconds(long);
+    method public long toEpochMilli();
+    method public java.time.Instant truncatedTo(java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.Instant with(java.time.temporal.TemporalField, long);
+    field public static final java.time.Instant EPOCH;
+    field public static final java.time.Instant MAX;
+    field public static final java.time.Instant MIN;
+  }
+
+  public final class LocalDate implements java.time.chrono.ChronoLocalDate java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.LocalDateTime atStartOfDay();
+    method public java.time.ZonedDateTime atStartOfDay(java.time.ZoneId);
+    method public java.time.LocalDateTime atTime(int, int);
+    method public java.time.LocalDateTime atTime(int, int, int);
+    method public java.time.LocalDateTime atTime(int, int, int, int);
+    method public java.time.OffsetDateTime atTime(java.time.OffsetTime);
+    method public static java.time.LocalDate from(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.IsoChronology getChronology();
+    method public int getDayOfMonth();
+    method public java.time.DayOfWeek getDayOfWeek();
+    method public int getDayOfYear();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public java.time.Month getMonth();
+    method public int getMonthValue();
+    method public int getYear();
+    method public int lengthOfMonth();
+    method public java.time.LocalDate minusDays(long);
+    method public java.time.LocalDate minusMonths(long);
+    method public java.time.LocalDate minusWeeks(long);
+    method public java.time.LocalDate minusYears(long);
+    method public static java.time.LocalDate now();
+    method public static java.time.LocalDate now(java.time.ZoneId);
+    method public static java.time.LocalDate now(java.time.Clock);
+    method public static java.time.LocalDate of(int, java.time.Month, int);
+    method public static java.time.LocalDate of(int, int, int);
+    method public static java.time.LocalDate ofEpochDay(long);
+    method public static java.time.LocalDate ofYearDay(int, int);
+    method public static java.time.LocalDate parse(java.lang.CharSequence);
+    method public static java.time.LocalDate parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.LocalDate plusDays(long);
+    method public java.time.LocalDate plusMonths(long);
+    method public java.time.LocalDate plusWeeks(long);
+    method public java.time.LocalDate plusYears(long);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.Period until(java.time.chrono.ChronoLocalDate);
+    method public java.time.LocalDate withDayOfMonth(int);
+    method public java.time.LocalDate withDayOfYear(int);
+    method public java.time.LocalDate withMonth(int);
+    method public java.time.LocalDate withYear(int);
+    field public static final java.time.LocalDate MAX;
+    field public static final java.time.LocalDate MIN;
+  }
+
+  public final class LocalDateTime implements java.time.chrono.ChronoLocalDateTime java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.OffsetDateTime atOffset(java.time.ZoneOffset);
+    method public java.time.ZonedDateTime atZone(java.time.ZoneId);
+    method public static java.time.LocalDateTime from(java.time.temporal.TemporalAccessor);
+    method public int getDayOfMonth();
+    method public java.time.DayOfWeek getDayOfWeek();
+    method public int getDayOfYear();
+    method public int getHour();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getMinute();
+    method public java.time.Month getMonth();
+    method public int getMonthValue();
+    method public int getNano();
+    method public int getSecond();
+    method public int getYear();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public java.time.LocalDateTime minusDays(long);
+    method public java.time.LocalDateTime minusHours(long);
+    method public java.time.LocalDateTime minusMinutes(long);
+    method public java.time.LocalDateTime minusMonths(long);
+    method public java.time.LocalDateTime minusNanos(long);
+    method public java.time.LocalDateTime minusSeconds(long);
+    method public java.time.LocalDateTime minusWeeks(long);
+    method public java.time.LocalDateTime minusYears(long);
+    method public static java.time.LocalDateTime now();
+    method public static java.time.LocalDateTime now(java.time.ZoneId);
+    method public static java.time.LocalDateTime now(java.time.Clock);
+    method public static java.time.LocalDateTime of(int, java.time.Month, int, int, int);
+    method public static java.time.LocalDateTime of(int, java.time.Month, int, int, int, int);
+    method public static java.time.LocalDateTime of(int, java.time.Month, int, int, int, int, int);
+    method public static java.time.LocalDateTime of(int, int, int, int, int);
+    method public static java.time.LocalDateTime of(int, int, int, int, int, int);
+    method public static java.time.LocalDateTime of(int, int, int, int, int, int, int);
+    method public static java.time.LocalDateTime of(java.time.LocalDate, java.time.LocalTime);
+    method public static java.time.LocalDateTime ofEpochSecond(long, int, java.time.ZoneOffset);
+    method public static java.time.LocalDateTime ofInstant(java.time.Instant, java.time.ZoneId);
+    method public static java.time.LocalDateTime parse(java.lang.CharSequence);
+    method public static java.time.LocalDateTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.LocalDateTime plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.LocalDateTime plusDays(long);
+    method public java.time.LocalDateTime plusHours(long);
+    method public java.time.LocalDateTime plusMinutes(long);
+    method public java.time.LocalDateTime plusMonths(long);
+    method public java.time.LocalDateTime plusNanos(long);
+    method public java.time.LocalDateTime plusSeconds(long);
+    method public java.time.LocalDateTime plusWeeks(long);
+    method public java.time.LocalDateTime plusYears(long);
+    method public java.time.LocalDate toLocalDate();
+    method public java.time.LocalTime toLocalTime();
+    method public java.time.LocalDateTime truncatedTo(java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.LocalDateTime with(java.time.temporal.TemporalField, long);
+    method public java.time.LocalDateTime withDayOfMonth(int);
+    method public java.time.LocalDateTime withDayOfYear(int);
+    method public java.time.LocalDateTime withHour(int);
+    method public java.time.LocalDateTime withMinute(int);
+    method public java.time.LocalDateTime withMonth(int);
+    method public java.time.LocalDateTime withNano(int);
+    method public java.time.LocalDateTime withSecond(int);
+    method public java.time.LocalDateTime withYear(int);
+    field public static final java.time.LocalDateTime MAX;
+    field public static final java.time.LocalDateTime MIN;
+  }
+
+  public final class LocalTime implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.LocalDateTime atDate(java.time.LocalDate);
+    method public java.time.OffsetTime atOffset(java.time.ZoneOffset);
+    method public int compareTo(java.time.LocalTime);
+    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.LocalTime from(java.time.temporal.TemporalAccessor);
+    method public int getHour();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getMinute();
+    method public int getNano();
+    method public int getSecond();
+    method public boolean isAfter(java.time.LocalTime);
+    method public boolean isBefore(java.time.LocalTime);
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
+    method public java.time.LocalTime minusHours(long);
+    method public java.time.LocalTime minusMinutes(long);
+    method public java.time.LocalTime minusNanos(long);
+    method public java.time.LocalTime minusSeconds(long);
+    method public static java.time.LocalTime now();
+    method public static java.time.LocalTime now(java.time.ZoneId);
+    method public static java.time.LocalTime now(java.time.Clock);
+    method public static java.time.LocalTime of(int, int);
+    method public static java.time.LocalTime of(int, int, int);
+    method public static java.time.LocalTime of(int, int, int, int);
+    method public static java.time.LocalTime ofNanoOfDay(long);
+    method public static java.time.LocalTime ofSecondOfDay(long);
+    method public static java.time.LocalTime parse(java.lang.CharSequence);
+    method public static java.time.LocalTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.LocalTime plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.LocalTime plusHours(long);
+    method public java.time.LocalTime plusMinutes(long);
+    method public java.time.LocalTime plusNanos(long);
+    method public java.time.LocalTime plusSeconds(long);
+    method public long toNanoOfDay();
+    method public int toSecondOfDay();
+    method public java.time.LocalTime truncatedTo(java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.LocalTime with(java.time.temporal.TemporalField, long);
+    method public java.time.LocalTime withHour(int);
+    method public java.time.LocalTime withMinute(int);
+    method public java.time.LocalTime withNano(int);
+    method public java.time.LocalTime withSecond(int);
+    field public static final java.time.LocalTime MAX;
+    field public static final java.time.LocalTime MIDNIGHT;
+    field public static final java.time.LocalTime MIN;
+    field public static final java.time.LocalTime NOON;
+  }
+
+  public final class Month extends java.lang.Enum implements java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public int firstDayOfYear(boolean);
+    method public java.time.Month firstMonthOfQuarter();
+    method public static java.time.Month from(java.time.temporal.TemporalAccessor);
+    method public int get(java.time.temporal.TemporalField);
+    method public java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getValue();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public int length(boolean);
+    method public int maxLength();
+    method public int minLength();
+    method public java.time.Month minus(long);
+    method public static java.time.Month of(int);
+    method public java.time.Month plus(long);
+    method public <R> R query(java.time.temporal.TemporalQuery<R>);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public static java.time.Month valueOf(java.lang.String);
+    method public static final java.time.Month[] values();
+    enum_constant public static final java.time.Month APRIL;
+    enum_constant public static final java.time.Month AUGUST;
+    enum_constant public static final java.time.Month DECEMBER;
+    enum_constant public static final java.time.Month FEBRUARY;
+    enum_constant public static final java.time.Month JANUARY;
+    enum_constant public static final java.time.Month JULY;
+    enum_constant public static final java.time.Month JUNE;
+    enum_constant public static final java.time.Month MARCH;
+    enum_constant public static final java.time.Month MAY;
+    enum_constant public static final java.time.Month NOVEMBER;
+    enum_constant public static final java.time.Month OCTOBER;
+    enum_constant public static final java.time.Month SEPTEMBER;
+  }
+
+  public final class MonthDay implements java.lang.Comparable java.io.Serializable java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.LocalDate atYear(int);
+    method public int compareTo(java.time.MonthDay);
+    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.MonthDay from(java.time.temporal.TemporalAccessor);
+    method public int getDayOfMonth();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public java.time.Month getMonth();
+    method public int getMonthValue();
+    method public boolean isAfter(java.time.MonthDay);
+    method public boolean isBefore(java.time.MonthDay);
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isValidYear(int);
+    method public static java.time.MonthDay now();
+    method public static java.time.MonthDay now(java.time.ZoneId);
+    method public static java.time.MonthDay now(java.time.Clock);
+    method public static java.time.MonthDay of(java.time.Month, int);
+    method public static java.time.MonthDay of(int, int);
+    method public static java.time.MonthDay parse(java.lang.CharSequence);
+    method public static java.time.MonthDay parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.MonthDay with(java.time.Month);
+    method public java.time.MonthDay withDayOfMonth(int);
+    method public java.time.MonthDay withMonth(int);
+  }
+
+  public final class OffsetDateTime implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.ZonedDateTime atZoneSameInstant(java.time.ZoneId);
+    method public java.time.ZonedDateTime atZoneSimilarLocal(java.time.ZoneId);
+    method public int compareTo(java.time.OffsetDateTime);
+    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.OffsetDateTime from(java.time.temporal.TemporalAccessor);
+    method public int getDayOfMonth();
+    method public java.time.DayOfWeek getDayOfWeek();
+    method public int getDayOfYear();
+    method public int getHour();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getMinute();
+    method public java.time.Month getMonth();
+    method public int getMonthValue();
+    method public int getNano();
+    method public java.time.ZoneOffset getOffset();
+    method public int getSecond();
+    method public int getYear();
+    method public boolean isAfter(java.time.OffsetDateTime);
+    method public boolean isBefore(java.time.OffsetDateTime);
+    method public boolean isEqual(java.time.OffsetDateTime);
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
+    method public java.time.OffsetDateTime minusDays(long);
+    method public java.time.OffsetDateTime minusHours(long);
+    method public java.time.OffsetDateTime minusMinutes(long);
+    method public java.time.OffsetDateTime minusMonths(long);
+    method public java.time.OffsetDateTime minusNanos(long);
+    method public java.time.OffsetDateTime minusSeconds(long);
+    method public java.time.OffsetDateTime minusWeeks(long);
+    method public java.time.OffsetDateTime minusYears(long);
+    method public static java.time.OffsetDateTime now();
+    method public static java.time.OffsetDateTime now(java.time.ZoneId);
+    method public static java.time.OffsetDateTime now(java.time.Clock);
+    method public static java.time.OffsetDateTime of(java.time.LocalDate, java.time.LocalTime, java.time.ZoneOffset);
+    method public static java.time.OffsetDateTime of(java.time.LocalDateTime, java.time.ZoneOffset);
+    method public static java.time.OffsetDateTime of(int, int, int, int, int, int, int, java.time.ZoneOffset);
+    method public static java.time.OffsetDateTime ofInstant(java.time.Instant, java.time.ZoneId);
+    method public static java.time.OffsetDateTime parse(java.lang.CharSequence);
+    method public static java.time.OffsetDateTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.OffsetDateTime plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.OffsetDateTime plusDays(long);
+    method public java.time.OffsetDateTime plusHours(long);
+    method public java.time.OffsetDateTime plusMinutes(long);
+    method public java.time.OffsetDateTime plusMonths(long);
+    method public java.time.OffsetDateTime plusNanos(long);
+    method public java.time.OffsetDateTime plusSeconds(long);
+    method public java.time.OffsetDateTime plusWeeks(long);
+    method public java.time.OffsetDateTime plusYears(long);
+    method public static java.util.Comparator<java.time.OffsetDateTime> timeLineOrder();
+    method public long toEpochSecond();
+    method public java.time.Instant toInstant();
+    method public java.time.LocalDate toLocalDate();
+    method public java.time.LocalDateTime toLocalDateTime();
+    method public java.time.LocalTime toLocalTime();
+    method public java.time.OffsetTime toOffsetTime();
+    method public java.time.ZonedDateTime toZonedDateTime();
+    method public java.time.OffsetDateTime truncatedTo(java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.OffsetDateTime with(java.time.temporal.TemporalField, long);
+    method public java.time.OffsetDateTime withDayOfMonth(int);
+    method public java.time.OffsetDateTime withDayOfYear(int);
+    method public java.time.OffsetDateTime withHour(int);
+    method public java.time.OffsetDateTime withMinute(int);
+    method public java.time.OffsetDateTime withMonth(int);
+    method public java.time.OffsetDateTime withNano(int);
+    method public java.time.OffsetDateTime withOffsetSameInstant(java.time.ZoneOffset);
+    method public java.time.OffsetDateTime withOffsetSameLocal(java.time.ZoneOffset);
+    method public java.time.OffsetDateTime withSecond(int);
+    method public java.time.OffsetDateTime withYear(int);
+    field public static final java.time.OffsetDateTime MAX;
+    field public static final java.time.OffsetDateTime MIN;
+  }
+
+  public final class OffsetTime implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.OffsetDateTime atDate(java.time.LocalDate);
+    method public int compareTo(java.time.OffsetTime);
+    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.OffsetTime from(java.time.temporal.TemporalAccessor);
+    method public int getHour();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getMinute();
+    method public int getNano();
+    method public java.time.ZoneOffset getOffset();
+    method public int getSecond();
+    method public boolean isAfter(java.time.OffsetTime);
+    method public boolean isBefore(java.time.OffsetTime);
+    method public boolean isEqual(java.time.OffsetTime);
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
+    method public java.time.OffsetTime minusHours(long);
+    method public java.time.OffsetTime minusMinutes(long);
+    method public java.time.OffsetTime minusNanos(long);
+    method public java.time.OffsetTime minusSeconds(long);
+    method public static java.time.OffsetTime now();
+    method public static java.time.OffsetTime now(java.time.ZoneId);
+    method public static java.time.OffsetTime now(java.time.Clock);
+    method public static java.time.OffsetTime of(java.time.LocalTime, java.time.ZoneOffset);
+    method public static java.time.OffsetTime of(int, int, int, int, java.time.ZoneOffset);
+    method public static java.time.OffsetTime ofInstant(java.time.Instant, java.time.ZoneId);
+    method public static java.time.OffsetTime parse(java.lang.CharSequence);
+    method public static java.time.OffsetTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.OffsetTime plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.OffsetTime plusHours(long);
+    method public java.time.OffsetTime plusMinutes(long);
+    method public java.time.OffsetTime plusNanos(long);
+    method public java.time.OffsetTime plusSeconds(long);
+    method public java.time.LocalTime toLocalTime();
+    method public java.time.OffsetTime truncatedTo(java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.OffsetTime with(java.time.temporal.TemporalField, long);
+    method public java.time.OffsetTime withHour(int);
+    method public java.time.OffsetTime withMinute(int);
+    method public java.time.OffsetTime withNano(int);
+    method public java.time.OffsetTime withOffsetSameInstant(java.time.ZoneOffset);
+    method public java.time.OffsetTime withOffsetSameLocal(java.time.ZoneOffset);
+    method public java.time.OffsetTime withSecond(int);
+    field public static final java.time.OffsetTime MAX;
+    field public static final java.time.OffsetTime MIN;
+  }
+
+  public final class Period implements java.time.chrono.ChronoPeriod java.io.Serializable {
+    method public java.time.temporal.Temporal addTo(java.time.temporal.Temporal);
+    method public static java.time.Period between(java.time.LocalDate, java.time.LocalDate);
+    method public static java.time.Period from(java.time.temporal.TemporalAmount);
+    method public long get(java.time.temporal.TemporalUnit);
+    method public java.time.chrono.IsoChronology getChronology();
+    method public int getDays();
+    method public int getMonths();
+    method public java.util.List<java.time.temporal.TemporalUnit> getUnits();
+    method public int getYears();
+    method public java.time.Period minus(java.time.temporal.TemporalAmount);
+    method public java.time.Period minusDays(long);
+    method public java.time.Period minusMonths(long);
+    method public java.time.Period minusYears(long);
+    method public java.time.Period multipliedBy(int);
+    method public java.time.Period normalized();
+    method public static java.time.Period of(int, int, int);
+    method public static java.time.Period ofDays(int);
+    method public static java.time.Period ofMonths(int);
+    method public static java.time.Period ofWeeks(int);
+    method public static java.time.Period ofYears(int);
+    method public static java.time.Period parse(java.lang.CharSequence);
+    method public java.time.Period plus(java.time.temporal.TemporalAmount);
+    method public java.time.Period plusDays(long);
+    method public java.time.Period plusMonths(long);
+    method public java.time.Period plusYears(long);
+    method public java.time.temporal.Temporal subtractFrom(java.time.temporal.Temporal);
+    method public long toTotalMonths();
+    method public java.time.Period withDays(int);
+    method public java.time.Period withMonths(int);
+    method public java.time.Period withYears(int);
+    field public static final java.time.Period ZERO;
+  }
+
+  public final class Year implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.LocalDate atDay(int);
+    method public java.time.YearMonth atMonth(java.time.Month);
+    method public java.time.YearMonth atMonth(int);
+    method public java.time.LocalDate atMonthDay(java.time.MonthDay);
+    method public int compareTo(java.time.Year);
+    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.Year from(java.time.temporal.TemporalAccessor);
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getValue();
+    method public boolean isAfter(java.time.Year);
+    method public boolean isBefore(java.time.Year);
+    method public static boolean isLeap(long);
+    method public boolean isLeap();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
+    method public boolean isValidMonthDay(java.time.MonthDay);
+    method public int length();
+    method public java.time.Year minusYears(long);
+    method public static java.time.Year now();
+    method public static java.time.Year now(java.time.ZoneId);
+    method public static java.time.Year now(java.time.Clock);
+    method public static java.time.Year of(int);
+    method public static java.time.Year parse(java.lang.CharSequence);
+    method public static java.time.Year parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.Year plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.Year plusYears(long);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.Year with(java.time.temporal.TemporalField, long);
+    field public static final int MAX_VALUE = 999999999; // 0x3b9ac9ff
+    field public static final int MIN_VALUE = -999999999; // 0xc4653601
+  }
+
+  public final class YearMonth implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.LocalDate atDay(int);
+    method public java.time.LocalDate atEndOfMonth();
+    method public int compareTo(java.time.YearMonth);
+    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.YearMonth from(java.time.temporal.TemporalAccessor);
+    method public long getLong(java.time.temporal.TemporalField);
+    method public java.time.Month getMonth();
+    method public int getMonthValue();
+    method public int getYear();
+    method public boolean isAfter(java.time.YearMonth);
+    method public boolean isBefore(java.time.YearMonth);
+    method public boolean isLeapYear();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
+    method public boolean isValidDay(int);
+    method public int lengthOfMonth();
+    method public int lengthOfYear();
+    method public java.time.YearMonth minusMonths(long);
+    method public java.time.YearMonth minusYears(long);
+    method public static java.time.YearMonth now();
+    method public static java.time.YearMonth now(java.time.ZoneId);
+    method public static java.time.YearMonth now(java.time.Clock);
+    method public static java.time.YearMonth of(int, java.time.Month);
+    method public static java.time.YearMonth of(int, int);
+    method public static java.time.YearMonth parse(java.lang.CharSequence);
+    method public static java.time.YearMonth parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.YearMonth plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.YearMonth plusMonths(long);
+    method public java.time.YearMonth plusYears(long);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.YearMonth with(java.time.temporal.TemporalField, long);
+    method public java.time.YearMonth withMonth(int);
+    method public java.time.YearMonth withYear(int);
+  }
+
+  public abstract class ZoneId implements java.io.Serializable {
+    method public static java.time.ZoneId from(java.time.temporal.TemporalAccessor);
+    method public static java.util.Set<java.lang.String> getAvailableZoneIds();
+    method public java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public abstract java.lang.String getId();
+    method public abstract java.time.zone.ZoneRules getRules();
+    method public java.time.ZoneId normalized();
+    method public static java.time.ZoneId of(java.lang.String, java.util.Map<java.lang.String, java.lang.String>);
+    method public static java.time.ZoneId of(java.lang.String);
+    method public static java.time.ZoneId ofOffset(java.lang.String, java.time.ZoneOffset);
+    method public static java.time.ZoneId systemDefault();
+    field public static final java.util.Map<java.lang.String, java.lang.String> SHORT_IDS;
+  }
+
+  public final class ZoneOffset extends java.time.ZoneId implements java.lang.Comparable java.io.Serializable java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public int compareTo(java.time.ZoneOffset);
+    method public static java.time.ZoneOffset from(java.time.temporal.TemporalAccessor);
+    method public int get(java.time.temporal.TemporalField);
+    method public java.lang.String getId();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public java.time.zone.ZoneRules getRules();
+    method public int getTotalSeconds();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public static java.time.ZoneOffset of(java.lang.String);
+    method public static java.time.ZoneOffset ofHours(int);
+    method public static java.time.ZoneOffset ofHoursMinutes(int, int);
+    method public static java.time.ZoneOffset ofHoursMinutesSeconds(int, int, int);
+    method public static java.time.ZoneOffset ofTotalSeconds(int);
+    method public <R> R query(java.time.temporal.TemporalQuery<R>);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    field public static final java.time.ZoneOffset MAX;
+    field public static final java.time.ZoneOffset MIN;
+    field public static final java.time.ZoneOffset UTC;
+  }
+
+  public final class ZonedDateTime implements java.time.chrono.ChronoZonedDateTime java.io.Serializable java.time.temporal.Temporal {
+    method public static java.time.ZonedDateTime from(java.time.temporal.TemporalAccessor);
+    method public int getDayOfMonth();
+    method public java.time.DayOfWeek getDayOfWeek();
+    method public int getDayOfYear();
+    method public int getHour();
+    method public int getMinute();
+    method public java.time.Month getMonth();
+    method public int getMonthValue();
+    method public int getNano();
+    method public java.time.ZoneOffset getOffset();
+    method public int getSecond();
+    method public int getYear();
+    method public java.time.ZoneId getZone();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public java.time.ZonedDateTime minusDays(long);
+    method public java.time.ZonedDateTime minusHours(long);
+    method public java.time.ZonedDateTime minusMinutes(long);
+    method public java.time.ZonedDateTime minusMonths(long);
+    method public java.time.ZonedDateTime minusNanos(long);
+    method public java.time.ZonedDateTime minusSeconds(long);
+    method public java.time.ZonedDateTime minusWeeks(long);
+    method public java.time.ZonedDateTime minusYears(long);
+    method public static java.time.ZonedDateTime now();
+    method public static java.time.ZonedDateTime now(java.time.ZoneId);
+    method public static java.time.ZonedDateTime now(java.time.Clock);
+    method public static java.time.ZonedDateTime of(java.time.LocalDate, java.time.LocalTime, java.time.ZoneId);
+    method public static java.time.ZonedDateTime of(java.time.LocalDateTime, java.time.ZoneId);
+    method public static java.time.ZonedDateTime of(int, int, int, int, int, int, int, java.time.ZoneId);
+    method public static java.time.ZonedDateTime ofInstant(java.time.Instant, java.time.ZoneId);
+    method public static java.time.ZonedDateTime ofInstant(java.time.LocalDateTime, java.time.ZoneOffset, java.time.ZoneId);
+    method public static java.time.ZonedDateTime ofLocal(java.time.LocalDateTime, java.time.ZoneId, java.time.ZoneOffset);
+    method public static java.time.ZonedDateTime ofStrict(java.time.LocalDateTime, java.time.ZoneOffset, java.time.ZoneId);
+    method public static java.time.ZonedDateTime parse(java.lang.CharSequence);
+    method public static java.time.ZonedDateTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.ZonedDateTime plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.ZonedDateTime plusDays(long);
+    method public java.time.ZonedDateTime plusHours(long);
+    method public java.time.ZonedDateTime plusMinutes(long);
+    method public java.time.ZonedDateTime plusMonths(long);
+    method public java.time.ZonedDateTime plusNanos(long);
+    method public java.time.ZonedDateTime plusSeconds(long);
+    method public java.time.ZonedDateTime plusWeeks(long);
+    method public java.time.ZonedDateTime plusYears(long);
+    method public java.time.LocalDateTime toLocalDateTime();
+    method public java.time.OffsetDateTime toOffsetDateTime();
+    method public java.time.ZonedDateTime truncatedTo(java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.ZonedDateTime with(java.time.temporal.TemporalField, long);
+    method public java.time.ZonedDateTime withDayOfMonth(int);
+    method public java.time.ZonedDateTime withDayOfYear(int);
+    method public java.time.ZonedDateTime withEarlierOffsetAtOverlap();
+    method public java.time.ZonedDateTime withFixedOffsetZone();
+    method public java.time.ZonedDateTime withHour(int);
+    method public java.time.ZonedDateTime withLaterOffsetAtOverlap();
+    method public java.time.ZonedDateTime withMinute(int);
+    method public java.time.ZonedDateTime withMonth(int);
+    method public java.time.ZonedDateTime withNano(int);
+    method public java.time.ZonedDateTime withSecond(int);
+    method public java.time.ZonedDateTime withYear(int);
+    method public java.time.ZonedDateTime withZoneSameInstant(java.time.ZoneId);
+    method public java.time.ZonedDateTime withZoneSameLocal(java.time.ZoneId);
+  }
+
+}
+
+package java.time.chrono {
+
+  public abstract class AbstractChronology implements java.time.chrono.Chronology {
+    ctor protected AbstractChronology();
+    method public int compareTo(java.time.chrono.Chronology);
+    method public java.time.chrono.ChronoLocalDate resolveDate(java.util.Map<java.time.temporal.TemporalField, java.lang.Long>, java.time.format.ResolverStyle);
+  }
+
+  public abstract interface ChronoLocalDate implements java.lang.Comparable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public default java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public default java.time.chrono.ChronoLocalDateTime<?> atTime(java.time.LocalTime);
+    method public default int compareTo(java.time.chrono.ChronoLocalDate);
+    method public abstract boolean equals(java.lang.Object);
+    method public default java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.chrono.ChronoLocalDate from(java.time.temporal.TemporalAccessor);
+    method public abstract java.time.chrono.Chronology getChronology();
+    method public default java.time.chrono.Era getEra();
+    method public abstract int hashCode();
+    method public default boolean isAfter(java.time.chrono.ChronoLocalDate);
+    method public default boolean isBefore(java.time.chrono.ChronoLocalDate);
+    method public default boolean isEqual(java.time.chrono.ChronoLocalDate);
+    method public default boolean isLeapYear();
+    method public default boolean isSupported(java.time.temporal.TemporalField);
+    method public default boolean isSupported(java.time.temporal.TemporalUnit);
+    method public abstract int lengthOfMonth();
+    method public default int lengthOfYear();
+    method public default java.time.chrono.ChronoLocalDate plus(long, java.time.temporal.TemporalUnit);
+    method public static java.util.Comparator<java.time.chrono.ChronoLocalDate> timeLineOrder();
+    method public default long toEpochDay();
+    method public abstract java.lang.String toString();
+    method public abstract long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public abstract java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+    method public default java.time.chrono.ChronoLocalDate with(java.time.temporal.TemporalField, long);
+  }
+
+   abstract class ChronoLocalDateImpl<D extends java.time.chrono.ChronoLocalDate> implements java.time.chrono.ChronoLocalDate java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+  }
+
+  public abstract interface ChronoLocalDateTime<D extends java.time.chrono.ChronoLocalDate> implements java.lang.Comparable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public default java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> atZone(java.time.ZoneId);
+    method public default int compareTo(java.time.chrono.ChronoLocalDateTime<?>);
+    method public abstract boolean equals(java.lang.Object);
+    method public default java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.chrono.ChronoLocalDateTime<?> from(java.time.temporal.TemporalAccessor);
+    method public default java.time.chrono.Chronology getChronology();
+    method public abstract int hashCode();
+    method public default boolean isAfter(java.time.chrono.ChronoLocalDateTime<?>);
+    method public default boolean isBefore(java.time.chrono.ChronoLocalDateTime<?>);
+    method public default boolean isEqual(java.time.chrono.ChronoLocalDateTime<?>);
+    method public abstract boolean isSupported(java.time.temporal.TemporalField);
+    method public default boolean isSupported(java.time.temporal.TemporalUnit);
+    method public abstract java.time.chrono.ChronoLocalDateTime<D> plus(long, java.time.temporal.TemporalUnit);
+    method public static java.util.Comparator<java.time.chrono.ChronoLocalDateTime<?>> timeLineOrder();
+    method public default long toEpochSecond(java.time.ZoneOffset);
+    method public default java.time.Instant toInstant(java.time.ZoneOffset);
+    method public abstract D toLocalDate();
+    method public abstract java.time.LocalTime toLocalTime();
+    method public abstract java.lang.String toString();
+    method public abstract java.time.chrono.ChronoLocalDateTime<D> with(java.time.temporal.TemporalField, long);
+  }
+
+  public abstract interface ChronoPeriod implements java.time.temporal.TemporalAmount {
+    method public abstract java.time.temporal.Temporal addTo(java.time.temporal.Temporal);
+    method public static java.time.chrono.ChronoPeriod between(java.time.chrono.ChronoLocalDate, java.time.chrono.ChronoLocalDate);
+    method public abstract boolean equals(java.lang.Object);
+    method public abstract long get(java.time.temporal.TemporalUnit);
+    method public abstract java.time.chrono.Chronology getChronology();
+    method public abstract java.util.List<java.time.temporal.TemporalUnit> getUnits();
+    method public abstract int hashCode();
+    method public default boolean isNegative();
+    method public default boolean isZero();
+    method public abstract java.time.chrono.ChronoPeriod minus(java.time.temporal.TemporalAmount);
+    method public abstract java.time.chrono.ChronoPeriod multipliedBy(int);
+    method public default java.time.chrono.ChronoPeriod negated();
+    method public abstract java.time.chrono.ChronoPeriod normalized();
+    method public abstract java.time.chrono.ChronoPeriod plus(java.time.temporal.TemporalAmount);
+    method public abstract java.time.temporal.Temporal subtractFrom(java.time.temporal.Temporal);
+    method public abstract java.lang.String toString();
+  }
+
+  public abstract interface ChronoZonedDateTime<D extends java.time.chrono.ChronoLocalDate> implements java.lang.Comparable java.time.temporal.Temporal {
+    method public default int compareTo(java.time.chrono.ChronoZonedDateTime<?>);
+    method public abstract boolean equals(java.lang.Object);
+    method public default java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.chrono.ChronoZonedDateTime<?> from(java.time.temporal.TemporalAccessor);
+    method public default java.time.chrono.Chronology getChronology();
+    method public default long getLong(java.time.temporal.TemporalField);
+    method public abstract java.time.ZoneOffset getOffset();
+    method public abstract java.time.ZoneId getZone();
+    method public abstract int hashCode();
+    method public default boolean isAfter(java.time.chrono.ChronoZonedDateTime<?>);
+    method public default boolean isBefore(java.time.chrono.ChronoZonedDateTime<?>);
+    method public default boolean isEqual(java.time.chrono.ChronoZonedDateTime<?>);
+    method public abstract boolean isSupported(java.time.temporal.TemporalField);
+    method public default boolean isSupported(java.time.temporal.TemporalUnit);
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> plus(long, java.time.temporal.TemporalUnit);
+    method public static java.util.Comparator<java.time.chrono.ChronoZonedDateTime<?>> timeLineOrder();
+    method public default long toEpochSecond();
+    method public default java.time.Instant toInstant();
+    method public default D toLocalDate();
+    method public abstract java.time.chrono.ChronoLocalDateTime<D> toLocalDateTime();
+    method public default java.time.LocalTime toLocalTime();
+    method public abstract java.lang.String toString();
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> with(java.time.temporal.TemporalField, long);
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> withEarlierOffsetAtOverlap();
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> withLaterOffsetAtOverlap();
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> withZoneSameInstant(java.time.ZoneId);
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> withZoneSameLocal(java.time.ZoneId);
+  }
+
+  public abstract interface Chronology implements java.lang.Comparable {
+    method public abstract int compareTo(java.time.chrono.Chronology);
+    method public default java.time.chrono.ChronoLocalDate date(java.time.chrono.Era, int, int, int);
+    method public abstract java.time.chrono.ChronoLocalDate date(int, int, int);
+    method public abstract java.time.chrono.ChronoLocalDate date(java.time.temporal.TemporalAccessor);
+    method public abstract java.time.chrono.ChronoLocalDate dateEpochDay(long);
+    method public default java.time.chrono.ChronoLocalDate dateNow();
+    method public default java.time.chrono.ChronoLocalDate dateNow(java.time.ZoneId);
+    method public default java.time.chrono.ChronoLocalDate dateNow(java.time.Clock);
+    method public default java.time.chrono.ChronoLocalDate dateYearDay(java.time.chrono.Era, int, int);
+    method public abstract java.time.chrono.ChronoLocalDate dateYearDay(int, int);
+    method public abstract boolean equals(java.lang.Object);
+    method public abstract java.time.chrono.Era eraOf(int);
+    method public abstract java.util.List<java.time.chrono.Era> eras();
+    method public static java.time.chrono.Chronology from(java.time.temporal.TemporalAccessor);
+    method public static java.util.Set<java.time.chrono.Chronology> getAvailableChronologies();
+    method public abstract java.lang.String getCalendarType();
+    method public default java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public abstract java.lang.String getId();
+    method public abstract int hashCode();
+    method public abstract boolean isLeapYear(long);
+    method public default java.time.chrono.ChronoLocalDateTime<? extends java.time.chrono.ChronoLocalDate> localDateTime(java.time.temporal.TemporalAccessor);
+    method public static java.time.chrono.Chronology of(java.lang.String);
+    method public static java.time.chrono.Chronology ofLocale(java.util.Locale);
+    method public default java.time.chrono.ChronoPeriod period(int, int, int);
+    method public abstract int prolepticYear(java.time.chrono.Era, int);
+    method public abstract java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public abstract java.time.chrono.ChronoLocalDate resolveDate(java.util.Map<java.time.temporal.TemporalField, java.lang.Long>, java.time.format.ResolverStyle);
+    method public abstract java.lang.String toString();
+    method public default java.time.chrono.ChronoZonedDateTime<? extends java.time.chrono.ChronoLocalDate> zonedDateTime(java.time.temporal.TemporalAccessor);
+    method public default java.time.chrono.ChronoZonedDateTime<? extends java.time.chrono.ChronoLocalDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
+  }
+
+  public abstract interface Era implements java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+    method public default java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public default java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public default long getLong(java.time.temporal.TemporalField);
+    method public abstract int getValue();
+    method public default boolean isSupported(java.time.temporal.TemporalField);
+  }
+
+  public final class HijrahChronology extends java.time.chrono.AbstractChronology implements java.io.Serializable {
+    method public java.time.chrono.HijrahDate date(java.time.chrono.Era, int, int, int);
+    method public java.time.chrono.HijrahDate date(int, int, int);
+    method public java.time.chrono.HijrahDate date(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.HijrahDate dateEpochDay(long);
+    method public java.time.chrono.HijrahDate dateNow();
+    method public java.time.chrono.HijrahDate dateNow(java.time.ZoneId);
+    method public java.time.chrono.HijrahDate dateNow(java.time.Clock);
+    method public java.time.chrono.HijrahDate dateYearDay(java.time.chrono.Era, int, int);
+    method public java.time.chrono.HijrahDate dateYearDay(int, int);
+    method public java.time.chrono.HijrahEra eraOf(int);
+    method public java.util.List<java.time.chrono.Era> eras();
+    method public java.lang.String getCalendarType();
+    method public java.lang.String getId();
+    method public boolean isLeapYear(long);
+    method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.HijrahDate> localDateTime(java.time.temporal.TemporalAccessor);
+    method public int prolepticYear(java.time.chrono.Era, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.HijrahDate> zonedDateTime(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.HijrahDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
+    field public static final java.time.chrono.HijrahChronology INSTANCE;
+  }
+
+  public final class HijrahDate extends java.time.chrono.ChronoLocalDateImpl implements java.time.chrono.ChronoLocalDate java.io.Serializable {
+    method public final java.time.chrono.ChronoLocalDateTime<java.time.chrono.HijrahDate> atTime(java.time.LocalTime);
+    method public static java.time.chrono.HijrahDate from(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.HijrahChronology getChronology();
+    method public java.time.chrono.HijrahEra getEra();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public boolean isLeapYear();
+    method public int lengthOfMonth();
+    method public int lengthOfYear();
+    method public static java.time.chrono.HijrahDate now();
+    method public static java.time.chrono.HijrahDate now(java.time.ZoneId);
+    method public static java.time.chrono.HijrahDate now(java.time.Clock);
+    method public static java.time.chrono.HijrahDate of(int, int, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public long toEpochDay();
+    method public java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+    method public java.time.chrono.HijrahDate withVariant(java.time.chrono.HijrahChronology);
+  }
+
+  public final class HijrahEra extends java.lang.Enum implements java.time.chrono.Era {
+    method public int getValue();
+    method public static java.time.chrono.HijrahEra of(int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public static java.time.chrono.HijrahEra valueOf(java.lang.String);
+    method public static final java.time.chrono.HijrahEra[] values();
+    enum_constant public static final java.time.chrono.HijrahEra AH;
+  }
+
+  public final class IsoChronology extends java.time.chrono.AbstractChronology implements java.io.Serializable {
+    method public java.time.LocalDate date(java.time.chrono.Era, int, int, int);
+    method public java.time.LocalDate date(int, int, int);
+    method public java.time.LocalDate date(java.time.temporal.TemporalAccessor);
+    method public java.time.LocalDate dateEpochDay(long);
+    method public java.time.LocalDate dateNow();
+    method public java.time.LocalDate dateNow(java.time.ZoneId);
+    method public java.time.LocalDate dateNow(java.time.Clock);
+    method public java.time.LocalDate dateYearDay(java.time.chrono.Era, int, int);
+    method public java.time.LocalDate dateYearDay(int, int);
+    method public java.time.chrono.IsoEra eraOf(int);
+    method public java.util.List<java.time.chrono.Era> eras();
+    method public java.lang.String getCalendarType();
+    method public java.lang.String getId();
+    method public boolean isLeapYear(long);
+    method public java.time.LocalDateTime localDateTime(java.time.temporal.TemporalAccessor);
+    method public java.time.Period period(int, int, int);
+    method public int prolepticYear(java.time.chrono.Era, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public java.time.ZonedDateTime zonedDateTime(java.time.temporal.TemporalAccessor);
+    method public java.time.ZonedDateTime zonedDateTime(java.time.Instant, java.time.ZoneId);
+    field public static final java.time.chrono.IsoChronology INSTANCE;
+  }
+
+  public final class IsoEra extends java.lang.Enum implements java.time.chrono.Era {
+    method public int getValue();
+    method public static java.time.chrono.IsoEra of(int);
+    method public static java.time.chrono.IsoEra valueOf(java.lang.String);
+    method public static final java.time.chrono.IsoEra[] values();
+    enum_constant public static final java.time.chrono.IsoEra BCE;
+    enum_constant public static final java.time.chrono.IsoEra CE;
+  }
+
+  public final class JapaneseChronology extends java.time.chrono.AbstractChronology implements java.io.Serializable {
+    method public java.time.chrono.JapaneseDate date(java.time.chrono.Era, int, int, int);
+    method public java.time.chrono.JapaneseDate date(int, int, int);
+    method public java.time.chrono.JapaneseDate date(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.JapaneseDate dateEpochDay(long);
+    method public java.time.chrono.JapaneseDate dateNow();
+    method public java.time.chrono.JapaneseDate dateNow(java.time.ZoneId);
+    method public java.time.chrono.JapaneseDate dateNow(java.time.Clock);
+    method public java.time.chrono.JapaneseDate dateYearDay(java.time.chrono.Era, int, int);
+    method public java.time.chrono.JapaneseDate dateYearDay(int, int);
+    method public java.time.chrono.JapaneseEra eraOf(int);
+    method public java.util.List<java.time.chrono.Era> eras();
+    method public java.lang.String getCalendarType();
+    method public java.lang.String getId();
+    method public boolean isLeapYear(long);
+    method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.JapaneseDate> localDateTime(java.time.temporal.TemporalAccessor);
+    method public int prolepticYear(java.time.chrono.Era, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.JapaneseDate> zonedDateTime(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.JapaneseDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
+    field public static final java.time.chrono.JapaneseChronology INSTANCE;
+  }
+
+  public final class JapaneseDate extends java.time.chrono.ChronoLocalDateImpl implements java.time.chrono.ChronoLocalDate java.io.Serializable {
+    method public final java.time.chrono.ChronoLocalDateTime<java.time.chrono.JapaneseDate> atTime(java.time.LocalTime);
+    method public static java.time.chrono.JapaneseDate from(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.JapaneseChronology getChronology();
+    method public java.time.chrono.JapaneseEra getEra();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public int lengthOfMonth();
+    method public int lengthOfYear();
+    method public static java.time.chrono.JapaneseDate now();
+    method public static java.time.chrono.JapaneseDate now(java.time.ZoneId);
+    method public static java.time.chrono.JapaneseDate now(java.time.Clock);
+    method public static java.time.chrono.JapaneseDate of(java.time.chrono.JapaneseEra, int, int, int);
+    method public static java.time.chrono.JapaneseDate of(int, int, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public long toEpochDay();
+    method public java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+  }
+
+  public final class JapaneseEra implements java.time.chrono.Era java.io.Serializable {
+    method public int getValue();
+    method public static java.time.chrono.JapaneseEra of(int);
+    method public static java.time.chrono.JapaneseEra valueOf(java.lang.String);
+    method public static java.time.chrono.JapaneseEra[] values();
+    field public static final java.time.chrono.JapaneseEra HEISEI;
+    field public static final java.time.chrono.JapaneseEra MEIJI;
+    field public static final java.time.chrono.JapaneseEra SHOWA;
+    field public static final java.time.chrono.JapaneseEra TAISHO;
+  }
+
+  public final class MinguoChronology extends java.time.chrono.AbstractChronology implements java.io.Serializable {
+    method public java.time.chrono.MinguoDate date(java.time.chrono.Era, int, int, int);
+    method public java.time.chrono.MinguoDate date(int, int, int);
+    method public java.time.chrono.MinguoDate date(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.MinguoDate dateEpochDay(long);
+    method public java.time.chrono.MinguoDate dateNow();
+    method public java.time.chrono.MinguoDate dateNow(java.time.ZoneId);
+    method public java.time.chrono.MinguoDate dateNow(java.time.Clock);
+    method public java.time.chrono.MinguoDate dateYearDay(java.time.chrono.Era, int, int);
+    method public java.time.chrono.MinguoDate dateYearDay(int, int);
+    method public java.time.chrono.MinguoEra eraOf(int);
+    method public java.util.List<java.time.chrono.Era> eras();
+    method public java.lang.String getCalendarType();
+    method public java.lang.String getId();
+    method public boolean isLeapYear(long);
+    method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.MinguoDate> localDateTime(java.time.temporal.TemporalAccessor);
+    method public int prolepticYear(java.time.chrono.Era, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.MinguoDate> zonedDateTime(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.MinguoDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
+    field public static final java.time.chrono.MinguoChronology INSTANCE;
+  }
+
+  public final class MinguoDate extends java.time.chrono.ChronoLocalDateImpl implements java.time.chrono.ChronoLocalDate java.io.Serializable {
+    method public final java.time.chrono.ChronoLocalDateTime<java.time.chrono.MinguoDate> atTime(java.time.LocalTime);
+    method public static java.time.chrono.MinguoDate from(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.MinguoChronology getChronology();
+    method public java.time.chrono.MinguoEra getEra();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int lengthOfMonth();
+    method public static java.time.chrono.MinguoDate now();
+    method public static java.time.chrono.MinguoDate now(java.time.ZoneId);
+    method public static java.time.chrono.MinguoDate now(java.time.Clock);
+    method public static java.time.chrono.MinguoDate of(int, int, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public long toEpochDay();
+    method public java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+  }
+
+  public final class MinguoEra extends java.lang.Enum implements java.time.chrono.Era {
+    method public int getValue();
+    method public static java.time.chrono.MinguoEra of(int);
+    method public static java.time.chrono.MinguoEra valueOf(java.lang.String);
+    method public static final java.time.chrono.MinguoEra[] values();
+    enum_constant public static final java.time.chrono.MinguoEra BEFORE_ROC;
+    enum_constant public static final java.time.chrono.MinguoEra ROC;
+  }
+
+  public final class ThaiBuddhistChronology extends java.time.chrono.AbstractChronology implements java.io.Serializable {
+    method public java.time.chrono.ThaiBuddhistDate date(java.time.chrono.Era, int, int, int);
+    method public java.time.chrono.ThaiBuddhistDate date(int, int, int);
+    method public java.time.chrono.ThaiBuddhistDate date(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ThaiBuddhistDate dateEpochDay(long);
+    method public java.time.chrono.ThaiBuddhistDate dateNow();
+    method public java.time.chrono.ThaiBuddhistDate dateNow(java.time.ZoneId);
+    method public java.time.chrono.ThaiBuddhistDate dateNow(java.time.Clock);
+    method public java.time.chrono.ThaiBuddhistDate dateYearDay(java.time.chrono.Era, int, int);
+    method public java.time.chrono.ThaiBuddhistDate dateYearDay(int, int);
+    method public java.time.chrono.ThaiBuddhistEra eraOf(int);
+    method public java.util.List<java.time.chrono.Era> eras();
+    method public java.lang.String getCalendarType();
+    method public java.lang.String getId();
+    method public boolean isLeapYear(long);
+    method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.ThaiBuddhistDate> localDateTime(java.time.temporal.TemporalAccessor);
+    method public int prolepticYear(java.time.chrono.Era, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.ThaiBuddhistDate> zonedDateTime(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.ThaiBuddhistDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
+    field public static final java.time.chrono.ThaiBuddhistChronology INSTANCE;
+  }
+
+  public final class ThaiBuddhistDate extends java.time.chrono.ChronoLocalDateImpl implements java.time.chrono.ChronoLocalDate java.io.Serializable {
+    method public final java.time.chrono.ChronoLocalDateTime<java.time.chrono.ThaiBuddhistDate> atTime(java.time.LocalTime);
+    method public static java.time.chrono.ThaiBuddhistDate from(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ThaiBuddhistChronology getChronology();
+    method public java.time.chrono.ThaiBuddhistEra getEra();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int lengthOfMonth();
+    method public static java.time.chrono.ThaiBuddhistDate now();
+    method public static java.time.chrono.ThaiBuddhistDate now(java.time.ZoneId);
+    method public static java.time.chrono.ThaiBuddhistDate now(java.time.Clock);
+    method public static java.time.chrono.ThaiBuddhistDate of(int, int, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public long toEpochDay();
+    method public java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+  }
+
+  public final class ThaiBuddhistEra extends java.lang.Enum implements java.time.chrono.Era {
+    method public int getValue();
+    method public static java.time.chrono.ThaiBuddhistEra of(int);
+    method public static java.time.chrono.ThaiBuddhistEra valueOf(java.lang.String);
+    method public static final java.time.chrono.ThaiBuddhistEra[] values();
+    enum_constant public static final java.time.chrono.ThaiBuddhistEra BE;
+    enum_constant public static final java.time.chrono.ThaiBuddhistEra BEFORE_BE;
+  }
+
+}
+
+package java.time.format {
+
+  public final class DateTimeFormatter {
+    method public java.lang.String format(java.time.temporal.TemporalAccessor);
+    method public void formatTo(java.time.temporal.TemporalAccessor, java.lang.Appendable);
+    method public java.time.chrono.Chronology getChronology();
+    method public java.time.format.DecimalStyle getDecimalStyle();
+    method public java.util.Locale getLocale();
+    method public java.util.Set<java.time.temporal.TemporalField> getResolverFields();
+    method public java.time.format.ResolverStyle getResolverStyle();
+    method public java.time.ZoneId getZone();
+    method public static java.time.format.DateTimeFormatter ofLocalizedDate(java.time.format.FormatStyle);
+    method public static java.time.format.DateTimeFormatter ofLocalizedDateTime(java.time.format.FormatStyle);
+    method public static java.time.format.DateTimeFormatter ofLocalizedDateTime(java.time.format.FormatStyle, java.time.format.FormatStyle);
+    method public static java.time.format.DateTimeFormatter ofLocalizedTime(java.time.format.FormatStyle);
+    method public static java.time.format.DateTimeFormatter ofPattern(java.lang.String);
+    method public static java.time.format.DateTimeFormatter ofPattern(java.lang.String, java.util.Locale);
+    method public java.time.temporal.TemporalAccessor parse(java.lang.CharSequence);
+    method public java.time.temporal.TemporalAccessor parse(java.lang.CharSequence, java.text.ParsePosition);
+    method public <T> T parse(java.lang.CharSequence, java.time.temporal.TemporalQuery<T>);
+    method public java.time.temporal.TemporalAccessor parseBest(java.lang.CharSequence, java.time.temporal.TemporalQuery<?>...);
+    method public java.time.temporal.TemporalAccessor parseUnresolved(java.lang.CharSequence, java.text.ParsePosition);
+    method public static final java.time.temporal.TemporalQuery<java.time.Period> parsedExcessDays();
+    method public static final java.time.temporal.TemporalQuery<java.lang.Boolean> parsedLeapSecond();
+    method public java.text.Format toFormat();
+    method public java.text.Format toFormat(java.time.temporal.TemporalQuery<?>);
+    method public java.time.format.DateTimeFormatter withChronology(java.time.chrono.Chronology);
+    method public java.time.format.DateTimeFormatter withDecimalStyle(java.time.format.DecimalStyle);
+    method public java.time.format.DateTimeFormatter withLocale(java.util.Locale);
+    method public java.time.format.DateTimeFormatter withResolverFields(java.time.temporal.TemporalField...);
+    method public java.time.format.DateTimeFormatter withResolverFields(java.util.Set<java.time.temporal.TemporalField>);
+    method public java.time.format.DateTimeFormatter withResolverStyle(java.time.format.ResolverStyle);
+    method public java.time.format.DateTimeFormatter withZone(java.time.ZoneId);
+    field public static final java.time.format.DateTimeFormatter BASIC_ISO_DATE;
+    field public static final java.time.format.DateTimeFormatter ISO_DATE;
+    field public static final java.time.format.DateTimeFormatter ISO_DATE_TIME;
+    field public static final java.time.format.DateTimeFormatter ISO_INSTANT;
+    field public static final java.time.format.DateTimeFormatter ISO_LOCAL_DATE;
+    field public static final java.time.format.DateTimeFormatter ISO_LOCAL_DATE_TIME;
+    field public static final java.time.format.DateTimeFormatter ISO_LOCAL_TIME;
+    field public static final java.time.format.DateTimeFormatter ISO_OFFSET_DATE;
+    field public static final java.time.format.DateTimeFormatter ISO_OFFSET_DATE_TIME;
+    field public static final java.time.format.DateTimeFormatter ISO_OFFSET_TIME;
+    field public static final java.time.format.DateTimeFormatter ISO_ORDINAL_DATE;
+    field public static final java.time.format.DateTimeFormatter ISO_TIME;
+    field public static final java.time.format.DateTimeFormatter ISO_WEEK_DATE;
+    field public static final java.time.format.DateTimeFormatter ISO_ZONED_DATE_TIME;
+    field public static final java.time.format.DateTimeFormatter RFC_1123_DATE_TIME;
+  }
+
+  public final class DateTimeFormatterBuilder {
+    ctor public DateTimeFormatterBuilder();
+    method public java.time.format.DateTimeFormatterBuilder append(java.time.format.DateTimeFormatter);
+    method public java.time.format.DateTimeFormatterBuilder appendChronologyId();
+    method public java.time.format.DateTimeFormatterBuilder appendChronologyText(java.time.format.TextStyle);
+    method public java.time.format.DateTimeFormatterBuilder appendFraction(java.time.temporal.TemporalField, int, int, boolean);
+    method public java.time.format.DateTimeFormatterBuilder appendInstant();
+    method public java.time.format.DateTimeFormatterBuilder appendInstant(int);
+    method public java.time.format.DateTimeFormatterBuilder appendLiteral(char);
+    method public java.time.format.DateTimeFormatterBuilder appendLiteral(java.lang.String);
+    method public java.time.format.DateTimeFormatterBuilder appendLocalized(java.time.format.FormatStyle, java.time.format.FormatStyle);
+    method public java.time.format.DateTimeFormatterBuilder appendLocalizedOffset(java.time.format.TextStyle);
+    method public java.time.format.DateTimeFormatterBuilder appendOffset(java.lang.String, java.lang.String);
+    method public java.time.format.DateTimeFormatterBuilder appendOffsetId();
+    method public java.time.format.DateTimeFormatterBuilder appendOptional(java.time.format.DateTimeFormatter);
+    method public java.time.format.DateTimeFormatterBuilder appendPattern(java.lang.String);
+    method public java.time.format.DateTimeFormatterBuilder appendText(java.time.temporal.TemporalField);
+    method public java.time.format.DateTimeFormatterBuilder appendText(java.time.temporal.TemporalField, java.time.format.TextStyle);
+    method public java.time.format.DateTimeFormatterBuilder appendText(java.time.temporal.TemporalField, java.util.Map<java.lang.Long, java.lang.String>);
+    method public java.time.format.DateTimeFormatterBuilder appendValue(java.time.temporal.TemporalField);
+    method public java.time.format.DateTimeFormatterBuilder appendValue(java.time.temporal.TemporalField, int);
+    method public java.time.format.DateTimeFormatterBuilder appendValue(java.time.temporal.TemporalField, int, int, java.time.format.SignStyle);
+    method public java.time.format.DateTimeFormatterBuilder appendValueReduced(java.time.temporal.TemporalField, int, int, int);
+    method public java.time.format.DateTimeFormatterBuilder appendValueReduced(java.time.temporal.TemporalField, int, int, java.time.chrono.ChronoLocalDate);
+    method public java.time.format.DateTimeFormatterBuilder appendZoneId();
+    method public java.time.format.DateTimeFormatterBuilder appendZoneOrOffsetId();
+    method public java.time.format.DateTimeFormatterBuilder appendZoneRegionId();
+    method public java.time.format.DateTimeFormatterBuilder appendZoneText(java.time.format.TextStyle);
+    method public java.time.format.DateTimeFormatterBuilder appendZoneText(java.time.format.TextStyle, java.util.Set<java.time.ZoneId>);
+    method public static java.lang.String getLocalizedDateTimePattern(java.time.format.FormatStyle, java.time.format.FormatStyle, java.time.chrono.Chronology, java.util.Locale);
+    method public java.time.format.DateTimeFormatterBuilder optionalEnd();
+    method public java.time.format.DateTimeFormatterBuilder optionalStart();
+    method public java.time.format.DateTimeFormatterBuilder padNext(int);
+    method public java.time.format.DateTimeFormatterBuilder padNext(int, char);
+    method public java.time.format.DateTimeFormatterBuilder parseCaseInsensitive();
+    method public java.time.format.DateTimeFormatterBuilder parseCaseSensitive();
+    method public java.time.format.DateTimeFormatterBuilder parseDefaulting(java.time.temporal.TemporalField, long);
+    method public java.time.format.DateTimeFormatterBuilder parseLenient();
+    method public java.time.format.DateTimeFormatterBuilder parseStrict();
+    method public java.time.format.DateTimeFormatter toFormatter();
+    method public java.time.format.DateTimeFormatter toFormatter(java.util.Locale);
+  }
+
+  public class DateTimeParseException extends java.time.DateTimeException {
+    ctor public DateTimeParseException(java.lang.String, java.lang.CharSequence, int);
+    ctor public DateTimeParseException(java.lang.String, java.lang.CharSequence, int, java.lang.Throwable);
+    method public int getErrorIndex();
+    method public java.lang.String getParsedString();
+  }
+
+  public final class DecimalStyle {
+    method public static java.util.Set<java.util.Locale> getAvailableLocales();
+    method public char getDecimalSeparator();
+    method public char getNegativeSign();
+    method public char getPositiveSign();
+    method public char getZeroDigit();
+    method public static java.time.format.DecimalStyle of(java.util.Locale);
+    method public static java.time.format.DecimalStyle ofDefaultLocale();
+    method public java.time.format.DecimalStyle withDecimalSeparator(char);
+    method public java.time.format.DecimalStyle withNegativeSign(char);
+    method public java.time.format.DecimalStyle withPositiveSign(char);
+    method public java.time.format.DecimalStyle withZeroDigit(char);
+    field public static final java.time.format.DecimalStyle STANDARD;
+  }
+
+  public final class FormatStyle extends java.lang.Enum {
+    method public static java.time.format.FormatStyle valueOf(java.lang.String);
+    method public static final java.time.format.FormatStyle[] values();
+    enum_constant public static final java.time.format.FormatStyle FULL;
+    enum_constant public static final java.time.format.FormatStyle LONG;
+    enum_constant public static final java.time.format.FormatStyle MEDIUM;
+    enum_constant public static final java.time.format.FormatStyle SHORT;
+  }
+
+  public final class ResolverStyle extends java.lang.Enum {
+    method public static java.time.format.ResolverStyle valueOf(java.lang.String);
+    method public static final java.time.format.ResolverStyle[] values();
+    enum_constant public static final java.time.format.ResolverStyle LENIENT;
+    enum_constant public static final java.time.format.ResolverStyle SMART;
+    enum_constant public static final java.time.format.ResolverStyle STRICT;
+  }
+
+  public final class SignStyle extends java.lang.Enum {
+    method public static java.time.format.SignStyle valueOf(java.lang.String);
+    method public static final java.time.format.SignStyle[] values();
+    enum_constant public static final java.time.format.SignStyle ALWAYS;
+    enum_constant public static final java.time.format.SignStyle EXCEEDS_PAD;
+    enum_constant public static final java.time.format.SignStyle NEVER;
+    enum_constant public static final java.time.format.SignStyle NORMAL;
+    enum_constant public static final java.time.format.SignStyle NOT_NEGATIVE;
+  }
+
+  public final class TextStyle extends java.lang.Enum {
+    method public java.time.format.TextStyle asNormal();
+    method public java.time.format.TextStyle asStandalone();
+    method public boolean isStandalone();
+    method public static java.time.format.TextStyle valueOf(java.lang.String);
+    method public static final java.time.format.TextStyle[] values();
+    enum_constant public static final java.time.format.TextStyle FULL;
+    enum_constant public static final java.time.format.TextStyle FULL_STANDALONE;
+    enum_constant public static final java.time.format.TextStyle NARROW;
+    enum_constant public static final java.time.format.TextStyle NARROW_STANDALONE;
+    enum_constant public static final java.time.format.TextStyle SHORT;
+    enum_constant public static final java.time.format.TextStyle SHORT_STANDALONE;
+  }
+
+}
+
+package java.time.temporal {
+
+  public final class ChronoField extends java.lang.Enum implements java.time.temporal.TemporalField {
+    method public <R extends java.time.temporal.Temporal> R adjustInto(R, long);
+    method public int checkValidIntValue(long);
+    method public long checkValidValue(long);
+    method public java.time.temporal.TemporalUnit getBaseUnit();
+    method public java.lang.String getDisplayName(java.util.Locale);
+    method public long getFrom(java.time.temporal.TemporalAccessor);
+    method public java.time.temporal.TemporalUnit getRangeUnit();
+    method public boolean isDateBased();
+    method public boolean isSupportedBy(java.time.temporal.TemporalAccessor);
+    method public boolean isTimeBased();
+    method public java.time.temporal.ValueRange range();
+    method public java.time.temporal.ValueRange rangeRefinedBy(java.time.temporal.TemporalAccessor);
+    method public static java.time.temporal.ChronoField valueOf(java.lang.String);
+    method public static final java.time.temporal.ChronoField[] values();
+    enum_constant public static final java.time.temporal.ChronoField ALIGNED_DAY_OF_WEEK_IN_MONTH;
+    enum_constant public static final java.time.temporal.ChronoField ALIGNED_DAY_OF_WEEK_IN_YEAR;
+    enum_constant public static final java.time.temporal.ChronoField ALIGNED_WEEK_OF_MONTH;
+    enum_constant public static final java.time.temporal.ChronoField ALIGNED_WEEK_OF_YEAR;
+    enum_constant public static final java.time.temporal.ChronoField AMPM_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField CLOCK_HOUR_OF_AMPM;
+    enum_constant public static final java.time.temporal.ChronoField CLOCK_HOUR_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField DAY_OF_MONTH;
+    enum_constant public static final java.time.temporal.ChronoField DAY_OF_WEEK;
+    enum_constant public static final java.time.temporal.ChronoField DAY_OF_YEAR;
+    enum_constant public static final java.time.temporal.ChronoField EPOCH_DAY;
+    enum_constant public static final java.time.temporal.ChronoField ERA;
+    enum_constant public static final java.time.temporal.ChronoField HOUR_OF_AMPM;
+    enum_constant public static final java.time.temporal.ChronoField HOUR_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField INSTANT_SECONDS;
+    enum_constant public static final java.time.temporal.ChronoField MICRO_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField MICRO_OF_SECOND;
+    enum_constant public static final java.time.temporal.ChronoField MILLI_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField MILLI_OF_SECOND;
+    enum_constant public static final java.time.temporal.ChronoField MINUTE_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField MINUTE_OF_HOUR;
+    enum_constant public static final java.time.temporal.ChronoField MONTH_OF_YEAR;
+    enum_constant public static final java.time.temporal.ChronoField NANO_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField NANO_OF_SECOND;
+    enum_constant public static final java.time.temporal.ChronoField OFFSET_SECONDS;
+    enum_constant public static final java.time.temporal.ChronoField PROLEPTIC_MONTH;
+    enum_constant public static final java.time.temporal.ChronoField SECOND_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField SECOND_OF_MINUTE;
+    enum_constant public static final java.time.temporal.ChronoField YEAR;
+    enum_constant public static final java.time.temporal.ChronoField YEAR_OF_ERA;
+  }
+
+  public final class ChronoUnit extends java.lang.Enum implements java.time.temporal.TemporalUnit {
+    method public <R extends java.time.temporal.Temporal> R addTo(R, long);
+    method public long between(java.time.temporal.Temporal, java.time.temporal.Temporal);
+    method public java.time.Duration getDuration();
+    method public boolean isDateBased();
+    method public boolean isDurationEstimated();
+    method public boolean isSupportedBy(java.time.temporal.Temporal);
+    method public boolean isTimeBased();
+    method public static java.time.temporal.ChronoUnit valueOf(java.lang.String);
+    method public static final java.time.temporal.ChronoUnit[] values();
+    enum_constant public static final java.time.temporal.ChronoUnit CENTURIES;
+    enum_constant public static final java.time.temporal.ChronoUnit DAYS;
+    enum_constant public static final java.time.temporal.ChronoUnit DECADES;
+    enum_constant public static final java.time.temporal.ChronoUnit ERAS;
+    enum_constant public static final java.time.temporal.ChronoUnit FOREVER;
+    enum_constant public static final java.time.temporal.ChronoUnit HALF_DAYS;
+    enum_constant public static final java.time.temporal.ChronoUnit HOURS;
+    enum_constant public static final java.time.temporal.ChronoUnit MICROS;
+    enum_constant public static final java.time.temporal.ChronoUnit MILLENNIA;
+    enum_constant public static final java.time.temporal.ChronoUnit MILLIS;
+    enum_constant public static final java.time.temporal.ChronoUnit MINUTES;
+    enum_constant public static final java.time.temporal.ChronoUnit MONTHS;
+    enum_constant public static final java.time.temporal.ChronoUnit NANOS;
+    enum_constant public static final java.time.temporal.ChronoUnit SECONDS;
+    enum_constant public static final java.time.temporal.ChronoUnit WEEKS;
+    enum_constant public static final java.time.temporal.ChronoUnit YEARS;
+  }
+
+  public final class IsoFields {
+    field public static final java.time.temporal.TemporalField DAY_OF_QUARTER;
+    field public static final java.time.temporal.TemporalField QUARTER_OF_YEAR;
+    field public static final java.time.temporal.TemporalUnit QUARTER_YEARS;
+    field public static final java.time.temporal.TemporalField WEEK_BASED_YEAR;
+    field public static final java.time.temporal.TemporalUnit WEEK_BASED_YEARS;
+    field public static final java.time.temporal.TemporalField WEEK_OF_WEEK_BASED_YEAR;
+  }
+
+  public final class JulianFields {
+    field public static final java.time.temporal.TemporalField JULIAN_DAY;
+    field public static final java.time.temporal.TemporalField MODIFIED_JULIAN_DAY;
+    field public static final java.time.temporal.TemporalField RATA_DIE;
+  }
+
+  public abstract interface Temporal implements java.time.temporal.TemporalAccessor {
+    method public abstract boolean isSupported(java.time.temporal.TemporalUnit);
+    method public default java.time.temporal.Temporal minus(java.time.temporal.TemporalAmount);
+    method public default java.time.temporal.Temporal minus(long, java.time.temporal.TemporalUnit);
+    method public default java.time.temporal.Temporal plus(java.time.temporal.TemporalAmount);
+    method public abstract java.time.temporal.Temporal plus(long, java.time.temporal.TemporalUnit);
+    method public abstract long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public default java.time.temporal.Temporal with(java.time.temporal.TemporalAdjuster);
+    method public abstract java.time.temporal.Temporal with(java.time.temporal.TemporalField, long);
+  }
+
+  public abstract interface TemporalAccessor {
+    method public default int get(java.time.temporal.TemporalField);
+    method public abstract long getLong(java.time.temporal.TemporalField);
+    method public abstract boolean isSupported(java.time.temporal.TemporalField);
+    method public default <R> R query(java.time.temporal.TemporalQuery<R>);
+    method public default java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+  }
+
+  public abstract interface TemporalAdjuster {
+    method public abstract java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+  }
+
+  public final class TemporalAdjusters {
+    method public static java.time.temporal.TemporalAdjuster dayOfWeekInMonth(int, java.time.DayOfWeek);
+    method public static java.time.temporal.TemporalAdjuster firstDayOfMonth();
+    method public static java.time.temporal.TemporalAdjuster firstDayOfNextMonth();
+    method public static java.time.temporal.TemporalAdjuster firstDayOfNextYear();
+    method public static java.time.temporal.TemporalAdjuster firstDayOfYear();
+    method public static java.time.temporal.TemporalAdjuster firstInMonth(java.time.DayOfWeek);
+    method public static java.time.temporal.TemporalAdjuster lastDayOfMonth();
+    method public static java.time.temporal.TemporalAdjuster lastDayOfYear();
+    method public static java.time.temporal.TemporalAdjuster lastInMonth(java.time.DayOfWeek);
+    method public static java.time.temporal.TemporalAdjuster next(java.time.DayOfWeek);
+    method public static java.time.temporal.TemporalAdjuster nextOrSame(java.time.DayOfWeek);
+    method public static java.time.temporal.TemporalAdjuster ofDateAdjuster(java.util.function.UnaryOperator<java.time.LocalDate>);
+    method public static java.time.temporal.TemporalAdjuster previous(java.time.DayOfWeek);
+    method public static java.time.temporal.TemporalAdjuster previousOrSame(java.time.DayOfWeek);
+  }
+
+  public abstract interface TemporalAmount {
+    method public abstract java.time.temporal.Temporal addTo(java.time.temporal.Temporal);
+    method public abstract long get(java.time.temporal.TemporalUnit);
+    method public abstract java.util.List<java.time.temporal.TemporalUnit> getUnits();
+    method public abstract java.time.temporal.Temporal subtractFrom(java.time.temporal.Temporal);
+  }
+
+  public abstract interface TemporalField {
+    method public abstract <R extends java.time.temporal.Temporal> R adjustInto(R, long);
+    method public abstract java.time.temporal.TemporalUnit getBaseUnit();
+    method public default java.lang.String getDisplayName(java.util.Locale);
+    method public abstract long getFrom(java.time.temporal.TemporalAccessor);
+    method public abstract java.time.temporal.TemporalUnit getRangeUnit();
+    method public abstract boolean isDateBased();
+    method public abstract boolean isSupportedBy(java.time.temporal.TemporalAccessor);
+    method public abstract boolean isTimeBased();
+    method public abstract java.time.temporal.ValueRange range();
+    method public abstract java.time.temporal.ValueRange rangeRefinedBy(java.time.temporal.TemporalAccessor);
+    method public default java.time.temporal.TemporalAccessor resolve(java.util.Map<java.time.temporal.TemporalField, java.lang.Long>, java.time.temporal.TemporalAccessor, java.time.format.ResolverStyle);
+    method public abstract java.lang.String toString();
+  }
+
+  public final class TemporalQueries {
+    method public static java.time.temporal.TemporalQuery<java.time.chrono.Chronology> chronology();
+    method public static java.time.temporal.TemporalQuery<java.time.LocalDate> localDate();
+    method public static java.time.temporal.TemporalQuery<java.time.LocalTime> localTime();
+    method public static java.time.temporal.TemporalQuery<java.time.ZoneOffset> offset();
+    method public static java.time.temporal.TemporalQuery<java.time.temporal.TemporalUnit> precision();
+    method public static java.time.temporal.TemporalQuery<java.time.ZoneId> zone();
+    method public static java.time.temporal.TemporalQuery<java.time.ZoneId> zoneId();
+  }
+
+  public abstract interface TemporalQuery<R> {
+    method public abstract R queryFrom(java.time.temporal.TemporalAccessor);
+  }
+
+  public abstract interface TemporalUnit {
+    method public abstract <R extends java.time.temporal.Temporal> R addTo(R, long);
+    method public abstract long between(java.time.temporal.Temporal, java.time.temporal.Temporal);
+    method public abstract java.time.Duration getDuration();
+    method public abstract boolean isDateBased();
+    method public abstract boolean isDurationEstimated();
+    method public default boolean isSupportedBy(java.time.temporal.Temporal);
+    method public abstract boolean isTimeBased();
+    method public abstract java.lang.String toString();
+  }
+
+  public class UnsupportedTemporalTypeException extends java.time.DateTimeException {
+    ctor public UnsupportedTemporalTypeException(java.lang.String);
+    ctor public UnsupportedTemporalTypeException(java.lang.String, java.lang.Throwable);
+  }
+
+  public final class ValueRange implements java.io.Serializable {
+    method public int checkValidIntValue(long, java.time.temporal.TemporalField);
+    method public long checkValidValue(long, java.time.temporal.TemporalField);
+    method public long getLargestMinimum();
+    method public long getMaximum();
+    method public long getMinimum();
+    method public long getSmallestMaximum();
+    method public boolean isFixed();
+    method public boolean isIntValue();
+    method public boolean isValidIntValue(long);
+    method public boolean isValidValue(long);
+    method public static java.time.temporal.ValueRange of(long, long);
+    method public static java.time.temporal.ValueRange of(long, long, long);
+    method public static java.time.temporal.ValueRange of(long, long, long, long);
+  }
+
+  public final class WeekFields implements java.io.Serializable {
+    method public java.time.temporal.TemporalField dayOfWeek();
+    method public java.time.DayOfWeek getFirstDayOfWeek();
+    method public int getMinimalDaysInFirstWeek();
+    method public static java.time.temporal.WeekFields of(java.util.Locale);
+    method public static java.time.temporal.WeekFields of(java.time.DayOfWeek, int);
+    method public java.time.temporal.TemporalField weekBasedYear();
+    method public java.time.temporal.TemporalField weekOfMonth();
+    method public java.time.temporal.TemporalField weekOfWeekBasedYear();
+    method public java.time.temporal.TemporalField weekOfYear();
+    field public static final java.time.temporal.WeekFields ISO;
+    field public static final java.time.temporal.WeekFields SUNDAY_START;
+    field public static final java.time.temporal.TemporalUnit WEEK_BASED_YEARS;
+  }
+
+}
+
+package java.time.zone {
+
+  public final class ZoneOffsetTransition implements java.lang.Comparable java.io.Serializable {
+    method public int compareTo(java.time.zone.ZoneOffsetTransition);
+    method public java.time.LocalDateTime getDateTimeAfter();
+    method public java.time.LocalDateTime getDateTimeBefore();
+    method public java.time.Duration getDuration();
+    method public java.time.Instant getInstant();
+    method public java.time.ZoneOffset getOffsetAfter();
+    method public java.time.ZoneOffset getOffsetBefore();
+    method public boolean isGap();
+    method public boolean isOverlap();
+    method public boolean isValidOffset(java.time.ZoneOffset);
+    method public static java.time.zone.ZoneOffsetTransition of(java.time.LocalDateTime, java.time.ZoneOffset, java.time.ZoneOffset);
+    method public long toEpochSecond();
+  }
+
+  public final class ZoneOffsetTransitionRule implements java.io.Serializable {
+    method public java.time.zone.ZoneOffsetTransition createTransition(int);
+    method public int getDayOfMonthIndicator();
+    method public java.time.DayOfWeek getDayOfWeek();
+    method public java.time.LocalTime getLocalTime();
+    method public java.time.Month getMonth();
+    method public java.time.ZoneOffset getOffsetAfter();
+    method public java.time.ZoneOffset getOffsetBefore();
+    method public java.time.ZoneOffset getStandardOffset();
+    method public java.time.zone.ZoneOffsetTransitionRule.TimeDefinition getTimeDefinition();
+    method public boolean isMidnightEndOfDay();
+    method public static java.time.zone.ZoneOffsetTransitionRule of(java.time.Month, int, java.time.DayOfWeek, java.time.LocalTime, boolean, java.time.zone.ZoneOffsetTransitionRule.TimeDefinition, java.time.ZoneOffset, java.time.ZoneOffset, java.time.ZoneOffset);
+  }
+
+  public static final class ZoneOffsetTransitionRule.TimeDefinition extends java.lang.Enum {
+    method public java.time.LocalDateTime createDateTime(java.time.LocalDateTime, java.time.ZoneOffset, java.time.ZoneOffset);
+    method public static java.time.zone.ZoneOffsetTransitionRule.TimeDefinition valueOf(java.lang.String);
+    method public static final java.time.zone.ZoneOffsetTransitionRule.TimeDefinition[] values();
+    enum_constant public static final java.time.zone.ZoneOffsetTransitionRule.TimeDefinition STANDARD;
+    enum_constant public static final java.time.zone.ZoneOffsetTransitionRule.TimeDefinition UTC;
+    enum_constant public static final java.time.zone.ZoneOffsetTransitionRule.TimeDefinition WALL;
+  }
+
+  public final class ZoneRules implements java.io.Serializable {
+    method public java.time.Duration getDaylightSavings(java.time.Instant);
+    method public java.time.ZoneOffset getOffset(java.time.Instant);
+    method public java.time.ZoneOffset getOffset(java.time.LocalDateTime);
+    method public java.time.ZoneOffset getStandardOffset(java.time.Instant);
+    method public java.time.zone.ZoneOffsetTransition getTransition(java.time.LocalDateTime);
+    method public java.util.List<java.time.zone.ZoneOffsetTransitionRule> getTransitionRules();
+    method public java.util.List<java.time.zone.ZoneOffsetTransition> getTransitions();
+    method public java.util.List<java.time.ZoneOffset> getValidOffsets(java.time.LocalDateTime);
+    method public boolean isDaylightSavings(java.time.Instant);
+    method public boolean isFixedOffset();
+    method public boolean isValidOffset(java.time.LocalDateTime, java.time.ZoneOffset);
+    method public java.time.zone.ZoneOffsetTransition nextTransition(java.time.Instant);
+    method public static java.time.zone.ZoneRules of(java.time.ZoneOffset, java.time.ZoneOffset, java.util.List<java.time.zone.ZoneOffsetTransition>, java.util.List<java.time.zone.ZoneOffsetTransition>, java.util.List<java.time.zone.ZoneOffsetTransitionRule>);
+    method public static java.time.zone.ZoneRules of(java.time.ZoneOffset);
+    method public java.time.zone.ZoneOffsetTransition previousTransition(java.time.Instant);
+  }
+
+  public class ZoneRulesException extends java.time.DateTimeException {
+    ctor public ZoneRulesException(java.lang.String);
+    ctor public ZoneRulesException(java.lang.String, java.lang.Throwable);
+  }
+
+}
+
 package java.util {
 
   public abstract class AbstractCollection<E> implements java.util.Collection {
@@ -62275,7 +63934,9 @@
     method public int get(int);
     method public int getActualMaximum(int);
     method public int getActualMinimum(int);
+    method public static java.util.Set<java.lang.String> getAvailableCalendarTypes();
     method public static synchronized java.util.Locale[] getAvailableLocales();
+    method public java.lang.String getCalendarType();
     method public java.lang.String getDisplayName(int, int, java.util.Locale);
     method public java.util.Map<java.lang.String, java.lang.Integer> getDisplayNames(int, int, java.util.Locale);
     method public int getFirstDayOfWeek();
@@ -62310,6 +63971,7 @@
     method public void setTimeInMillis(long);
     method public void setTimeZone(java.util.TimeZone);
     method public void setWeekDate(int, int, int);
+    method public final java.time.Instant toInstant();
     field public static final int ALL_STYLES = 0; // 0x0
     field public static final int AM = 0; // 0x0
     field public static final int AM_PM = 9; // 0x9
@@ -62332,12 +63994,16 @@
     field public static final int JULY = 6; // 0x6
     field public static final int JUNE = 5; // 0x5
     field public static final int LONG = 2; // 0x2
+    field public static final int LONG_FORMAT = 2; // 0x2
+    field public static final int LONG_STANDALONE = 32770; // 0x8002
     field public static final int MARCH = 2; // 0x2
     field public static final int MAY = 4; // 0x4
     field public static final int MILLISECOND = 14; // 0xe
     field public static final int MINUTE = 12; // 0xc
     field public static final int MONDAY = 2; // 0x2
     field public static final int MONTH = 2; // 0x2
+    field public static final int NARROW_FORMAT = 4; // 0x4
+    field public static final int NARROW_STANDALONE = 32772; // 0x8004
     field public static final int NOVEMBER = 10; // 0xa
     field public static final int OCTOBER = 9; // 0x9
     field public static final int PM = 1; // 0x1
@@ -62345,6 +64011,8 @@
     field public static final int SECOND = 13; // 0xd
     field public static final int SEPTEMBER = 8; // 0x8
     field public static final int SHORT = 1; // 0x1
+    field public static final int SHORT_FORMAT = 1; // 0x1
+    field public static final int SHORT_STANDALONE = 32769; // 0x8001
     field public static final int SUNDAY = 1; // 0x1
     field public static final int THURSDAY = 5; // 0x5
     field public static final int TUESDAY = 3; // 0x3
@@ -62361,6 +64029,24 @@
     field protected long time;
   }
 
+  public static class Calendar.Builder {
+    ctor public Calendar.Builder();
+    method public java.util.Calendar build();
+    method public java.util.Calendar.Builder set(int, int);
+    method public java.util.Calendar.Builder setCalendarType(java.lang.String);
+    method public java.util.Calendar.Builder setDate(int, int, int);
+    method public java.util.Calendar.Builder setFields(int...);
+    method public java.util.Calendar.Builder setInstant(long);
+    method public java.util.Calendar.Builder setInstant(java.util.Date);
+    method public java.util.Calendar.Builder setLenient(boolean);
+    method public java.util.Calendar.Builder setLocale(java.util.Locale);
+    method public java.util.Calendar.Builder setTimeOfDay(int, int, int);
+    method public java.util.Calendar.Builder setTimeOfDay(int, int, int, int);
+    method public java.util.Calendar.Builder setTimeZone(java.util.TimeZone);
+    method public java.util.Calendar.Builder setWeekDate(int, int, int);
+    method public java.util.Calendar.Builder setWeekDefinition(int, int);
+  }
+
   public abstract interface Collection<E> implements java.lang.Iterable {
     method public abstract boolean add(E);
     method public abstract boolean addAll(java.util.Collection<? extends E>);
@@ -62496,6 +64182,7 @@
     method public boolean before(java.util.Date);
     method public java.lang.Object clone();
     method public int compareTo(java.util.Date);
+    method public static java.util.Date from(java.time.Instant);
     method public deprecated int getDate();
     method public deprecated int getDay();
     method public deprecated int getHours();
@@ -62514,6 +64201,7 @@
     method public void setTime(long);
     method public deprecated void setYear(int);
     method public deprecated java.lang.String toGMTString();
+    method public java.time.Instant toInstant();
     method public deprecated java.lang.String toLocaleString();
   }
 
@@ -62683,6 +64371,7 @@
     method public void add(int, int);
     method protected void computeFields();
     method protected void computeTime();
+    method public static java.util.GregorianCalendar from(java.time.ZonedDateTime);
     method public int getGreatestMinimum(int);
     method public final java.util.Date getGregorianChange();
     method public int getLeastMaximum(int);
@@ -62692,6 +64381,7 @@
     method public final boolean isWeekDateSupported();
     method public void roll(int, boolean);
     method public void setGregorianChange(java.util.Date);
+    method public java.time.ZonedDateTime toZonedDateTime();
     field public static final int AD = 1; // 0x1
     field public static final int BC = 0; // 0x0
   }
@@ -63719,12 +65409,14 @@
     method public int getOffset(long);
     method public abstract int getRawOffset();
     method public static synchronized java.util.TimeZone getTimeZone(java.lang.String);
+    method public static java.util.TimeZone getTimeZone(java.time.ZoneId);
     method public boolean hasSameRules(java.util.TimeZone);
     method public abstract boolean inDaylightTime(java.util.Date);
     method public boolean observesDaylightTime();
     method public static synchronized void setDefault(java.util.TimeZone);
     method public void setID(java.lang.String);
     method public abstract void setRawOffset(int);
+    method public java.time.ZoneId toZoneId();
     method public abstract boolean useDaylightTime();
     field public static final int LONG = 1; // 0x1
     field public static final int SHORT = 0; // 0x0
@@ -64331,31 +66023,31 @@
     ctor public CopyOnWriteArrayList();
     ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
     ctor public CopyOnWriteArrayList(E[]);
-    method public synchronized boolean add(E);
-    method public synchronized void add(int, E);
-    method public synchronized boolean addAll(java.util.Collection<? extends E>);
-    method public synchronized boolean addAll(int, java.util.Collection<? extends E>);
-    method public synchronized int addAllAbsent(java.util.Collection<? extends E>);
-    method public synchronized boolean addIfAbsent(E);
-    method public synchronized void clear();
+    method public boolean add(E);
+    method public void add(int, E);
+    method public boolean addAll(java.util.Collection<? extends E>);
+    method public boolean addAll(int, java.util.Collection<? extends E>);
+    method public int addAllAbsent(java.util.Collection<? extends E>);
+    method public boolean addIfAbsent(E);
+    method public void clear();
     method public java.lang.Object clone();
     method public boolean contains(java.lang.Object);
     method public boolean containsAll(java.util.Collection<?>);
     method public void forEach(java.util.function.Consumer<? super E>);
     method public E get(int);
-    method public int indexOf(E, int);
     method public int indexOf(java.lang.Object);
+    method public int indexOf(E, int);
     method public boolean isEmpty();
     method public java.util.Iterator<E> iterator();
-    method public int lastIndexOf(E, int);
     method public int lastIndexOf(java.lang.Object);
-    method public java.util.ListIterator<E> listIterator(int);
+    method public int lastIndexOf(E, int);
     method public java.util.ListIterator<E> listIterator();
-    method public synchronized E remove(int);
-    method public synchronized boolean remove(java.lang.Object);
-    method public synchronized boolean removeAll(java.util.Collection<?>);
-    method public synchronized boolean retainAll(java.util.Collection<?>);
-    method public synchronized E set(int, E);
+    method public java.util.ListIterator<E> listIterator(int);
+    method public E remove(int);
+    method public boolean remove(java.lang.Object);
+    method public boolean removeAll(java.util.Collection<?>);
+    method public boolean retainAll(java.util.Collection<?>);
+    method public E set(int, E);
     method public int size();
     method public java.util.List<E> subList(int, int);
     method public java.lang.Object[] toArray();
@@ -66206,10 +67898,12 @@
     method public java.lang.StringBuffer appendTail(java.lang.StringBuffer);
     method public int end();
     method public int end(int);
+    method public int end(java.lang.String);
     method public boolean find();
     method public boolean find(int);
     method public java.lang.String group();
     method public java.lang.String group(int);
+    method public java.lang.String group(java.lang.String);
     method public int groupCount();
     method public boolean hasAnchoringBounds();
     method public boolean hasTransparentBounds();
@@ -66228,6 +67922,7 @@
     method public java.util.regex.Matcher reset(java.lang.CharSequence);
     method public int start();
     method public int start(int) throws java.lang.IllegalStateException;
+    method public int start(java.lang.String);
     method public java.util.regex.MatchResult toMatchResult();
     method public java.util.regex.Matcher useAnchoringBounds(boolean);
     method public java.util.regex.Matcher usePattern(java.util.regex.Pattern);
diff --git a/api/test-current.txt b/api/test-current.txt
index 5a2f607..2b0ca00 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -8237,6 +8237,7 @@
     field public static final java.lang.String USER_SERVICE = "user";
     field public static final java.lang.String VIBRATOR_SERVICE = "vibrator";
     field public static final java.lang.String WALLPAPER_SERVICE = "wallpaper";
+    field public static final java.lang.String WIFI_AWARE_SERVICE = "wifiaware";
     field public static final java.lang.String WIFI_P2P_SERVICE = "wifip2p";
     field public static final java.lang.String WIFI_SERVICE = "wifi";
     field public static final java.lang.String WINDOW_SERVICE = "window";
@@ -9902,6 +9903,7 @@
     field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
     field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
     field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
+    field public static final java.lang.String FEATURE_WIFI_AWARE = "android.hardware.wifi.aware";
     field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
     field public static final int GET_ACTIVITIES = 1; // 0x1
     field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
@@ -23844,6 +23846,7 @@
     field public static final int TRANSPORT_ETHERNET = 3; // 0x3
     field public static final int TRANSPORT_VPN = 4; // 0x4
     field public static final int TRANSPORT_WIFI = 1; // 0x1
+    field public static final int TRANSPORT_WIFI_AWARE = 5; // 0x5
   }
 
   public class NetworkInfo implements android.os.Parcelable {
@@ -24850,6 +24853,122 @@
 
 }
 
+package android.net.wifi.aware {
+
+  public class AttachCallback {
+    ctor public AttachCallback();
+    method public void onAttachFailed();
+    method public void onAttached(android.net.wifi.aware.WifiAwareSession);
+  }
+
+  public final class Characteristics implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getMaxMatchFilterLength();
+    method public int getMaxServiceNameLength();
+    method public int getMaxServiceSpecificInfoLength();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.aware.Characteristics> CREATOR;
+  }
+
+  public class DiscoverySession {
+    method public java.lang.String createNetworkSpecifier(android.net.wifi.aware.PeerHandle, byte[]);
+    method public void destroy();
+    method public static int getMaxSendRetryCount();
+    method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[], int);
+    method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
+  }
+
+  public class DiscoverySessionCallback {
+    ctor public DiscoverySessionCallback();
+    method public void onMessageReceived(android.net.wifi.aware.PeerHandle, byte[]);
+    method public void onMessageSendFailed(int);
+    method public void onMessageSendSucceeded(int);
+    method public void onPublishStarted(android.net.wifi.aware.PublishDiscoverySession);
+    method public void onServiceDiscovered(android.net.wifi.aware.PeerHandle, byte[], java.util.List<byte[]>);
+    method public void onSessionConfigFailed();
+    method public void onSessionConfigUpdated();
+    method public void onSessionTerminated();
+    method public void onSubscribeStarted(android.net.wifi.aware.SubscribeDiscoverySession);
+  }
+
+  public class IdentityChangedListener {
+    ctor public IdentityChangedListener();
+    method public void onIdentityChanged(byte[]);
+  }
+
+  public class PeerHandle {
+  }
+
+  public final class PublishConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.aware.PublishConfig> CREATOR;
+    field public static final int PUBLISH_TYPE_SOLICITED = 1; // 0x1
+    field public static final int PUBLISH_TYPE_UNSOLICITED = 0; // 0x0
+  }
+
+  public static final class PublishConfig.Builder {
+    ctor public PublishConfig.Builder();
+    method public android.net.wifi.aware.PublishConfig build();
+    method public android.net.wifi.aware.PublishConfig.Builder setMatchFilter(java.util.List<byte[]>);
+    method public android.net.wifi.aware.PublishConfig.Builder setPublishCount(int);
+    method public android.net.wifi.aware.PublishConfig.Builder setPublishType(int);
+    method public android.net.wifi.aware.PublishConfig.Builder setServiceName(java.lang.String);
+    method public android.net.wifi.aware.PublishConfig.Builder setServiceSpecificInfo(byte[]);
+    method public android.net.wifi.aware.PublishConfig.Builder setTerminateNotificationEnabled(boolean);
+    method public android.net.wifi.aware.PublishConfig.Builder setTtlSec(int);
+  }
+
+  public class PublishDiscoverySession extends android.net.wifi.aware.DiscoverySession {
+    method public void updatePublish(android.net.wifi.aware.PublishConfig);
+  }
+
+  public final class SubscribeConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.aware.SubscribeConfig> CREATOR;
+    field public static final int MATCH_STYLE_ALL = 1; // 0x1
+    field public static final int MATCH_STYLE_FIRST_ONLY = 0; // 0x0
+    field public static final int SUBSCRIBE_TYPE_ACTIVE = 1; // 0x1
+    field public static final int SUBSCRIBE_TYPE_PASSIVE = 0; // 0x0
+  }
+
+  public static final class SubscribeConfig.Builder {
+    ctor public SubscribeConfig.Builder();
+    method public android.net.wifi.aware.SubscribeConfig build();
+    method public android.net.wifi.aware.SubscribeConfig.Builder setMatchFilter(java.util.List<byte[]>);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setMatchStyle(int);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setServiceName(java.lang.String);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setServiceSpecificInfo(byte[]);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setSubscribeCount(int);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setSubscribeType(int);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setTerminateNotificationEnabled(boolean);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setTtlSec(int);
+  }
+
+  public class SubscribeDiscoverySession extends android.net.wifi.aware.DiscoverySession {
+    method public void updateSubscribe(android.net.wifi.aware.SubscribeConfig);
+  }
+
+  public class WifiAwareManager {
+    method public void attach(android.net.wifi.aware.AttachCallback, android.os.Handler);
+    method public void attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler);
+    method public android.net.wifi.aware.Characteristics getCharacteristics();
+    method public boolean isAvailable();
+    field public static final java.lang.String ACTION_WIFI_AWARE_STATE_CHANGED = "android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED";
+    field public static final int WIFI_AWARE_DATA_PATH_ROLE_INITIATOR = 0; // 0x0
+    field public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1; // 0x1
+  }
+
+  public class WifiAwareSession {
+    method public java.lang.String createNetworkSpecifier(int, byte[], byte[]);
+    method public void destroy();
+    method public void publish(android.net.wifi.aware.PublishConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler);
+    method public void subscribe(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler);
+  }
+
+}
+
 package android.net.wifi.p2p {
 
   public class WifiP2pConfig implements android.os.Parcelable {
@@ -54894,8 +55013,10 @@
   public final class FileTime implements java.lang.Comparable {
     method public int compareTo(java.nio.file.attribute.FileTime);
     method public static java.nio.file.attribute.FileTime from(long, java.util.concurrent.TimeUnit);
+    method public static java.nio.file.attribute.FileTime from(java.time.Instant);
     method public static java.nio.file.attribute.FileTime fromMillis(long);
     method public long to(java.util.concurrent.TimeUnit);
+    method public java.time.Instant toInstant();
     method public long toMillis();
   }
 
@@ -58425,6 +58546,1515 @@
 
 }
 
+package java.time {
+
+  public abstract class Clock {
+    ctor protected Clock();
+    method public static java.time.Clock fixed(java.time.Instant, java.time.ZoneId);
+    method public abstract java.time.ZoneId getZone();
+    method public abstract java.time.Instant instant();
+    method public long millis();
+    method public static java.time.Clock offset(java.time.Clock, java.time.Duration);
+    method public static java.time.Clock system(java.time.ZoneId);
+    method public static java.time.Clock systemDefaultZone();
+    method public static java.time.Clock systemUTC();
+    method public static java.time.Clock tick(java.time.Clock, java.time.Duration);
+    method public static java.time.Clock tickMinutes(java.time.ZoneId);
+    method public static java.time.Clock tickSeconds(java.time.ZoneId);
+    method public abstract java.time.Clock withZone(java.time.ZoneId);
+  }
+
+  public class DateTimeException extends java.lang.RuntimeException {
+    ctor public DateTimeException(java.lang.String);
+    ctor public DateTimeException(java.lang.String, java.lang.Throwable);
+  }
+
+  public final class DayOfWeek extends java.lang.Enum implements java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public static java.time.DayOfWeek from(java.time.temporal.TemporalAccessor);
+    method public int get(java.time.temporal.TemporalField);
+    method public java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getValue();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public java.time.DayOfWeek minus(long);
+    method public static java.time.DayOfWeek of(int);
+    method public java.time.DayOfWeek plus(long);
+    method public <R> R query(java.time.temporal.TemporalQuery<R>);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public static java.time.DayOfWeek valueOf(java.lang.String);
+    method public static final java.time.DayOfWeek[] values();
+    enum_constant public static final java.time.DayOfWeek FRIDAY;
+    enum_constant public static final java.time.DayOfWeek MONDAY;
+    enum_constant public static final java.time.DayOfWeek SATURDAY;
+    enum_constant public static final java.time.DayOfWeek SUNDAY;
+    enum_constant public static final java.time.DayOfWeek THURSDAY;
+    enum_constant public static final java.time.DayOfWeek TUESDAY;
+    enum_constant public static final java.time.DayOfWeek WEDNESDAY;
+  }
+
+  public final class Duration implements java.lang.Comparable java.io.Serializable java.time.temporal.TemporalAmount {
+    method public java.time.Duration abs();
+    method public java.time.temporal.Temporal addTo(java.time.temporal.Temporal);
+    method public static java.time.Duration between(java.time.temporal.Temporal, java.time.temporal.Temporal);
+    method public int compareTo(java.time.Duration);
+    method public java.time.Duration dividedBy(long);
+    method public static java.time.Duration from(java.time.temporal.TemporalAmount);
+    method public long get(java.time.temporal.TemporalUnit);
+    method public int getNano();
+    method public long getSeconds();
+    method public java.util.List<java.time.temporal.TemporalUnit> getUnits();
+    method public boolean isNegative();
+    method public boolean isZero();
+    method public java.time.Duration minus(java.time.Duration);
+    method public java.time.Duration minus(long, java.time.temporal.TemporalUnit);
+    method public java.time.Duration minusDays(long);
+    method public java.time.Duration minusHours(long);
+    method public java.time.Duration minusMillis(long);
+    method public java.time.Duration minusMinutes(long);
+    method public java.time.Duration minusNanos(long);
+    method public java.time.Duration minusSeconds(long);
+    method public java.time.Duration multipliedBy(long);
+    method public java.time.Duration negated();
+    method public static java.time.Duration of(long, java.time.temporal.TemporalUnit);
+    method public static java.time.Duration ofDays(long);
+    method public static java.time.Duration ofHours(long);
+    method public static java.time.Duration ofMillis(long);
+    method public static java.time.Duration ofMinutes(long);
+    method public static java.time.Duration ofNanos(long);
+    method public static java.time.Duration ofSeconds(long);
+    method public static java.time.Duration ofSeconds(long, long);
+    method public static java.time.Duration parse(java.lang.CharSequence);
+    method public java.time.Duration plus(java.time.Duration);
+    method public java.time.Duration plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.Duration plusDays(long);
+    method public java.time.Duration plusHours(long);
+    method public java.time.Duration plusMillis(long);
+    method public java.time.Duration plusMinutes(long);
+    method public java.time.Duration plusNanos(long);
+    method public java.time.Duration plusSeconds(long);
+    method public java.time.temporal.Temporal subtractFrom(java.time.temporal.Temporal);
+    method public long toDays();
+    method public long toHours();
+    method public long toMillis();
+    method public long toMinutes();
+    method public long toNanos();
+    method public java.time.Duration withNanos(int);
+    method public java.time.Duration withSeconds(long);
+    field public static final java.time.Duration ZERO;
+  }
+
+  public final class Instant implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.OffsetDateTime atOffset(java.time.ZoneOffset);
+    method public java.time.ZonedDateTime atZone(java.time.ZoneId);
+    method public int compareTo(java.time.Instant);
+    method public static java.time.Instant from(java.time.temporal.TemporalAccessor);
+    method public long getEpochSecond();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getNano();
+    method public boolean isAfter(java.time.Instant);
+    method public boolean isBefore(java.time.Instant);
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
+    method public java.time.Instant minusMillis(long);
+    method public java.time.Instant minusNanos(long);
+    method public java.time.Instant minusSeconds(long);
+    method public static java.time.Instant now();
+    method public static java.time.Instant now(java.time.Clock);
+    method public static java.time.Instant ofEpochMilli(long);
+    method public static java.time.Instant ofEpochSecond(long);
+    method public static java.time.Instant ofEpochSecond(long, long);
+    method public static java.time.Instant parse(java.lang.CharSequence);
+    method public java.time.Instant plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.Instant plusMillis(long);
+    method public java.time.Instant plusNanos(long);
+    method public java.time.Instant plusSeconds(long);
+    method public long toEpochMilli();
+    method public java.time.Instant truncatedTo(java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.Instant with(java.time.temporal.TemporalField, long);
+    field public static final java.time.Instant EPOCH;
+    field public static final java.time.Instant MAX;
+    field public static final java.time.Instant MIN;
+  }
+
+  public final class LocalDate implements java.time.chrono.ChronoLocalDate java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.LocalDateTime atStartOfDay();
+    method public java.time.ZonedDateTime atStartOfDay(java.time.ZoneId);
+    method public java.time.LocalDateTime atTime(int, int);
+    method public java.time.LocalDateTime atTime(int, int, int);
+    method public java.time.LocalDateTime atTime(int, int, int, int);
+    method public java.time.OffsetDateTime atTime(java.time.OffsetTime);
+    method public static java.time.LocalDate from(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.IsoChronology getChronology();
+    method public int getDayOfMonth();
+    method public java.time.DayOfWeek getDayOfWeek();
+    method public int getDayOfYear();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public java.time.Month getMonth();
+    method public int getMonthValue();
+    method public int getYear();
+    method public int lengthOfMonth();
+    method public java.time.LocalDate minusDays(long);
+    method public java.time.LocalDate minusMonths(long);
+    method public java.time.LocalDate minusWeeks(long);
+    method public java.time.LocalDate minusYears(long);
+    method public static java.time.LocalDate now();
+    method public static java.time.LocalDate now(java.time.ZoneId);
+    method public static java.time.LocalDate now(java.time.Clock);
+    method public static java.time.LocalDate of(int, java.time.Month, int);
+    method public static java.time.LocalDate of(int, int, int);
+    method public static java.time.LocalDate ofEpochDay(long);
+    method public static java.time.LocalDate ofYearDay(int, int);
+    method public static java.time.LocalDate parse(java.lang.CharSequence);
+    method public static java.time.LocalDate parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.LocalDate plusDays(long);
+    method public java.time.LocalDate plusMonths(long);
+    method public java.time.LocalDate plusWeeks(long);
+    method public java.time.LocalDate plusYears(long);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.Period until(java.time.chrono.ChronoLocalDate);
+    method public java.time.LocalDate withDayOfMonth(int);
+    method public java.time.LocalDate withDayOfYear(int);
+    method public java.time.LocalDate withMonth(int);
+    method public java.time.LocalDate withYear(int);
+    field public static final java.time.LocalDate MAX;
+    field public static final java.time.LocalDate MIN;
+  }
+
+  public final class LocalDateTime implements java.time.chrono.ChronoLocalDateTime java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.OffsetDateTime atOffset(java.time.ZoneOffset);
+    method public java.time.ZonedDateTime atZone(java.time.ZoneId);
+    method public static java.time.LocalDateTime from(java.time.temporal.TemporalAccessor);
+    method public int getDayOfMonth();
+    method public java.time.DayOfWeek getDayOfWeek();
+    method public int getDayOfYear();
+    method public int getHour();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getMinute();
+    method public java.time.Month getMonth();
+    method public int getMonthValue();
+    method public int getNano();
+    method public int getSecond();
+    method public int getYear();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public java.time.LocalDateTime minusDays(long);
+    method public java.time.LocalDateTime minusHours(long);
+    method public java.time.LocalDateTime minusMinutes(long);
+    method public java.time.LocalDateTime minusMonths(long);
+    method public java.time.LocalDateTime minusNanos(long);
+    method public java.time.LocalDateTime minusSeconds(long);
+    method public java.time.LocalDateTime minusWeeks(long);
+    method public java.time.LocalDateTime minusYears(long);
+    method public static java.time.LocalDateTime now();
+    method public static java.time.LocalDateTime now(java.time.ZoneId);
+    method public static java.time.LocalDateTime now(java.time.Clock);
+    method public static java.time.LocalDateTime of(int, java.time.Month, int, int, int);
+    method public static java.time.LocalDateTime of(int, java.time.Month, int, int, int, int);
+    method public static java.time.LocalDateTime of(int, java.time.Month, int, int, int, int, int);
+    method public static java.time.LocalDateTime of(int, int, int, int, int);
+    method public static java.time.LocalDateTime of(int, int, int, int, int, int);
+    method public static java.time.LocalDateTime of(int, int, int, int, int, int, int);
+    method public static java.time.LocalDateTime of(java.time.LocalDate, java.time.LocalTime);
+    method public static java.time.LocalDateTime ofEpochSecond(long, int, java.time.ZoneOffset);
+    method public static java.time.LocalDateTime ofInstant(java.time.Instant, java.time.ZoneId);
+    method public static java.time.LocalDateTime parse(java.lang.CharSequence);
+    method public static java.time.LocalDateTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.LocalDateTime plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.LocalDateTime plusDays(long);
+    method public java.time.LocalDateTime plusHours(long);
+    method public java.time.LocalDateTime plusMinutes(long);
+    method public java.time.LocalDateTime plusMonths(long);
+    method public java.time.LocalDateTime plusNanos(long);
+    method public java.time.LocalDateTime plusSeconds(long);
+    method public java.time.LocalDateTime plusWeeks(long);
+    method public java.time.LocalDateTime plusYears(long);
+    method public java.time.LocalDate toLocalDate();
+    method public java.time.LocalTime toLocalTime();
+    method public java.time.LocalDateTime truncatedTo(java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.LocalDateTime with(java.time.temporal.TemporalField, long);
+    method public java.time.LocalDateTime withDayOfMonth(int);
+    method public java.time.LocalDateTime withDayOfYear(int);
+    method public java.time.LocalDateTime withHour(int);
+    method public java.time.LocalDateTime withMinute(int);
+    method public java.time.LocalDateTime withMonth(int);
+    method public java.time.LocalDateTime withNano(int);
+    method public java.time.LocalDateTime withSecond(int);
+    method public java.time.LocalDateTime withYear(int);
+    field public static final java.time.LocalDateTime MAX;
+    field public static final java.time.LocalDateTime MIN;
+  }
+
+  public final class LocalTime implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.LocalDateTime atDate(java.time.LocalDate);
+    method public java.time.OffsetTime atOffset(java.time.ZoneOffset);
+    method public int compareTo(java.time.LocalTime);
+    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.LocalTime from(java.time.temporal.TemporalAccessor);
+    method public int getHour();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getMinute();
+    method public int getNano();
+    method public int getSecond();
+    method public boolean isAfter(java.time.LocalTime);
+    method public boolean isBefore(java.time.LocalTime);
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
+    method public java.time.LocalTime minusHours(long);
+    method public java.time.LocalTime minusMinutes(long);
+    method public java.time.LocalTime minusNanos(long);
+    method public java.time.LocalTime minusSeconds(long);
+    method public static java.time.LocalTime now();
+    method public static java.time.LocalTime now(java.time.ZoneId);
+    method public static java.time.LocalTime now(java.time.Clock);
+    method public static java.time.LocalTime of(int, int);
+    method public static java.time.LocalTime of(int, int, int);
+    method public static java.time.LocalTime of(int, int, int, int);
+    method public static java.time.LocalTime ofNanoOfDay(long);
+    method public static java.time.LocalTime ofSecondOfDay(long);
+    method public static java.time.LocalTime parse(java.lang.CharSequence);
+    method public static java.time.LocalTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.LocalTime plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.LocalTime plusHours(long);
+    method public java.time.LocalTime plusMinutes(long);
+    method public java.time.LocalTime plusNanos(long);
+    method public java.time.LocalTime plusSeconds(long);
+    method public long toNanoOfDay();
+    method public int toSecondOfDay();
+    method public java.time.LocalTime truncatedTo(java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.LocalTime with(java.time.temporal.TemporalField, long);
+    method public java.time.LocalTime withHour(int);
+    method public java.time.LocalTime withMinute(int);
+    method public java.time.LocalTime withNano(int);
+    method public java.time.LocalTime withSecond(int);
+    field public static final java.time.LocalTime MAX;
+    field public static final java.time.LocalTime MIDNIGHT;
+    field public static final java.time.LocalTime MIN;
+    field public static final java.time.LocalTime NOON;
+  }
+
+  public final class Month extends java.lang.Enum implements java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public int firstDayOfYear(boolean);
+    method public java.time.Month firstMonthOfQuarter();
+    method public static java.time.Month from(java.time.temporal.TemporalAccessor);
+    method public int get(java.time.temporal.TemporalField);
+    method public java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getValue();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public int length(boolean);
+    method public int maxLength();
+    method public int minLength();
+    method public java.time.Month minus(long);
+    method public static java.time.Month of(int);
+    method public java.time.Month plus(long);
+    method public <R> R query(java.time.temporal.TemporalQuery<R>);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public static java.time.Month valueOf(java.lang.String);
+    method public static final java.time.Month[] values();
+    enum_constant public static final java.time.Month APRIL;
+    enum_constant public static final java.time.Month AUGUST;
+    enum_constant public static final java.time.Month DECEMBER;
+    enum_constant public static final java.time.Month FEBRUARY;
+    enum_constant public static final java.time.Month JANUARY;
+    enum_constant public static final java.time.Month JULY;
+    enum_constant public static final java.time.Month JUNE;
+    enum_constant public static final java.time.Month MARCH;
+    enum_constant public static final java.time.Month MAY;
+    enum_constant public static final java.time.Month NOVEMBER;
+    enum_constant public static final java.time.Month OCTOBER;
+    enum_constant public static final java.time.Month SEPTEMBER;
+  }
+
+  public final class MonthDay implements java.lang.Comparable java.io.Serializable java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.LocalDate atYear(int);
+    method public int compareTo(java.time.MonthDay);
+    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.MonthDay from(java.time.temporal.TemporalAccessor);
+    method public int getDayOfMonth();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public java.time.Month getMonth();
+    method public int getMonthValue();
+    method public boolean isAfter(java.time.MonthDay);
+    method public boolean isBefore(java.time.MonthDay);
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isValidYear(int);
+    method public static java.time.MonthDay now();
+    method public static java.time.MonthDay now(java.time.ZoneId);
+    method public static java.time.MonthDay now(java.time.Clock);
+    method public static java.time.MonthDay of(java.time.Month, int);
+    method public static java.time.MonthDay of(int, int);
+    method public static java.time.MonthDay parse(java.lang.CharSequence);
+    method public static java.time.MonthDay parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.MonthDay with(java.time.Month);
+    method public java.time.MonthDay withDayOfMonth(int);
+    method public java.time.MonthDay withMonth(int);
+  }
+
+  public final class OffsetDateTime implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.ZonedDateTime atZoneSameInstant(java.time.ZoneId);
+    method public java.time.ZonedDateTime atZoneSimilarLocal(java.time.ZoneId);
+    method public int compareTo(java.time.OffsetDateTime);
+    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.OffsetDateTime from(java.time.temporal.TemporalAccessor);
+    method public int getDayOfMonth();
+    method public java.time.DayOfWeek getDayOfWeek();
+    method public int getDayOfYear();
+    method public int getHour();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getMinute();
+    method public java.time.Month getMonth();
+    method public int getMonthValue();
+    method public int getNano();
+    method public java.time.ZoneOffset getOffset();
+    method public int getSecond();
+    method public int getYear();
+    method public boolean isAfter(java.time.OffsetDateTime);
+    method public boolean isBefore(java.time.OffsetDateTime);
+    method public boolean isEqual(java.time.OffsetDateTime);
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
+    method public java.time.OffsetDateTime minusDays(long);
+    method public java.time.OffsetDateTime minusHours(long);
+    method public java.time.OffsetDateTime minusMinutes(long);
+    method public java.time.OffsetDateTime minusMonths(long);
+    method public java.time.OffsetDateTime minusNanos(long);
+    method public java.time.OffsetDateTime minusSeconds(long);
+    method public java.time.OffsetDateTime minusWeeks(long);
+    method public java.time.OffsetDateTime minusYears(long);
+    method public static java.time.OffsetDateTime now();
+    method public static java.time.OffsetDateTime now(java.time.ZoneId);
+    method public static java.time.OffsetDateTime now(java.time.Clock);
+    method public static java.time.OffsetDateTime of(java.time.LocalDate, java.time.LocalTime, java.time.ZoneOffset);
+    method public static java.time.OffsetDateTime of(java.time.LocalDateTime, java.time.ZoneOffset);
+    method public static java.time.OffsetDateTime of(int, int, int, int, int, int, int, java.time.ZoneOffset);
+    method public static java.time.OffsetDateTime ofInstant(java.time.Instant, java.time.ZoneId);
+    method public static java.time.OffsetDateTime parse(java.lang.CharSequence);
+    method public static java.time.OffsetDateTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.OffsetDateTime plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.OffsetDateTime plusDays(long);
+    method public java.time.OffsetDateTime plusHours(long);
+    method public java.time.OffsetDateTime plusMinutes(long);
+    method public java.time.OffsetDateTime plusMonths(long);
+    method public java.time.OffsetDateTime plusNanos(long);
+    method public java.time.OffsetDateTime plusSeconds(long);
+    method public java.time.OffsetDateTime plusWeeks(long);
+    method public java.time.OffsetDateTime plusYears(long);
+    method public static java.util.Comparator<java.time.OffsetDateTime> timeLineOrder();
+    method public long toEpochSecond();
+    method public java.time.Instant toInstant();
+    method public java.time.LocalDate toLocalDate();
+    method public java.time.LocalDateTime toLocalDateTime();
+    method public java.time.LocalTime toLocalTime();
+    method public java.time.OffsetTime toOffsetTime();
+    method public java.time.ZonedDateTime toZonedDateTime();
+    method public java.time.OffsetDateTime truncatedTo(java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.OffsetDateTime with(java.time.temporal.TemporalField, long);
+    method public java.time.OffsetDateTime withDayOfMonth(int);
+    method public java.time.OffsetDateTime withDayOfYear(int);
+    method public java.time.OffsetDateTime withHour(int);
+    method public java.time.OffsetDateTime withMinute(int);
+    method public java.time.OffsetDateTime withMonth(int);
+    method public java.time.OffsetDateTime withNano(int);
+    method public java.time.OffsetDateTime withOffsetSameInstant(java.time.ZoneOffset);
+    method public java.time.OffsetDateTime withOffsetSameLocal(java.time.ZoneOffset);
+    method public java.time.OffsetDateTime withSecond(int);
+    method public java.time.OffsetDateTime withYear(int);
+    field public static final java.time.OffsetDateTime MAX;
+    field public static final java.time.OffsetDateTime MIN;
+  }
+
+  public final class OffsetTime implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.OffsetDateTime atDate(java.time.LocalDate);
+    method public int compareTo(java.time.OffsetTime);
+    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.OffsetTime from(java.time.temporal.TemporalAccessor);
+    method public int getHour();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getMinute();
+    method public int getNano();
+    method public java.time.ZoneOffset getOffset();
+    method public int getSecond();
+    method public boolean isAfter(java.time.OffsetTime);
+    method public boolean isBefore(java.time.OffsetTime);
+    method public boolean isEqual(java.time.OffsetTime);
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
+    method public java.time.OffsetTime minusHours(long);
+    method public java.time.OffsetTime minusMinutes(long);
+    method public java.time.OffsetTime minusNanos(long);
+    method public java.time.OffsetTime minusSeconds(long);
+    method public static java.time.OffsetTime now();
+    method public static java.time.OffsetTime now(java.time.ZoneId);
+    method public static java.time.OffsetTime now(java.time.Clock);
+    method public static java.time.OffsetTime of(java.time.LocalTime, java.time.ZoneOffset);
+    method public static java.time.OffsetTime of(int, int, int, int, java.time.ZoneOffset);
+    method public static java.time.OffsetTime ofInstant(java.time.Instant, java.time.ZoneId);
+    method public static java.time.OffsetTime parse(java.lang.CharSequence);
+    method public static java.time.OffsetTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.OffsetTime plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.OffsetTime plusHours(long);
+    method public java.time.OffsetTime plusMinutes(long);
+    method public java.time.OffsetTime plusNanos(long);
+    method public java.time.OffsetTime plusSeconds(long);
+    method public java.time.LocalTime toLocalTime();
+    method public java.time.OffsetTime truncatedTo(java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.OffsetTime with(java.time.temporal.TemporalField, long);
+    method public java.time.OffsetTime withHour(int);
+    method public java.time.OffsetTime withMinute(int);
+    method public java.time.OffsetTime withNano(int);
+    method public java.time.OffsetTime withOffsetSameInstant(java.time.ZoneOffset);
+    method public java.time.OffsetTime withOffsetSameLocal(java.time.ZoneOffset);
+    method public java.time.OffsetTime withSecond(int);
+    field public static final java.time.OffsetTime MAX;
+    field public static final java.time.OffsetTime MIN;
+  }
+
+  public final class Period implements java.time.chrono.ChronoPeriod java.io.Serializable {
+    method public java.time.temporal.Temporal addTo(java.time.temporal.Temporal);
+    method public static java.time.Period between(java.time.LocalDate, java.time.LocalDate);
+    method public static java.time.Period from(java.time.temporal.TemporalAmount);
+    method public long get(java.time.temporal.TemporalUnit);
+    method public java.time.chrono.IsoChronology getChronology();
+    method public int getDays();
+    method public int getMonths();
+    method public java.util.List<java.time.temporal.TemporalUnit> getUnits();
+    method public int getYears();
+    method public java.time.Period minus(java.time.temporal.TemporalAmount);
+    method public java.time.Period minusDays(long);
+    method public java.time.Period minusMonths(long);
+    method public java.time.Period minusYears(long);
+    method public java.time.Period multipliedBy(int);
+    method public java.time.Period normalized();
+    method public static java.time.Period of(int, int, int);
+    method public static java.time.Period ofDays(int);
+    method public static java.time.Period ofMonths(int);
+    method public static java.time.Period ofWeeks(int);
+    method public static java.time.Period ofYears(int);
+    method public static java.time.Period parse(java.lang.CharSequence);
+    method public java.time.Period plus(java.time.temporal.TemporalAmount);
+    method public java.time.Period plusDays(long);
+    method public java.time.Period plusMonths(long);
+    method public java.time.Period plusYears(long);
+    method public java.time.temporal.Temporal subtractFrom(java.time.temporal.Temporal);
+    method public long toTotalMonths();
+    method public java.time.Period withDays(int);
+    method public java.time.Period withMonths(int);
+    method public java.time.Period withYears(int);
+    field public static final java.time.Period ZERO;
+  }
+
+  public final class Year implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.LocalDate atDay(int);
+    method public java.time.YearMonth atMonth(java.time.Month);
+    method public java.time.YearMonth atMonth(int);
+    method public java.time.LocalDate atMonthDay(java.time.MonthDay);
+    method public int compareTo(java.time.Year);
+    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.Year from(java.time.temporal.TemporalAccessor);
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int getValue();
+    method public boolean isAfter(java.time.Year);
+    method public boolean isBefore(java.time.Year);
+    method public static boolean isLeap(long);
+    method public boolean isLeap();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
+    method public boolean isValidMonthDay(java.time.MonthDay);
+    method public int length();
+    method public java.time.Year minusYears(long);
+    method public static java.time.Year now();
+    method public static java.time.Year now(java.time.ZoneId);
+    method public static java.time.Year now(java.time.Clock);
+    method public static java.time.Year of(int);
+    method public static java.time.Year parse(java.lang.CharSequence);
+    method public static java.time.Year parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.Year plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.Year plusYears(long);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.Year with(java.time.temporal.TemporalField, long);
+    field public static final int MAX_VALUE = 999999999; // 0x3b9ac9ff
+    field public static final int MIN_VALUE = -999999999; // 0xc4653601
+  }
+
+  public final class YearMonth implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public java.time.LocalDate atDay(int);
+    method public java.time.LocalDate atEndOfMonth();
+    method public int compareTo(java.time.YearMonth);
+    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.YearMonth from(java.time.temporal.TemporalAccessor);
+    method public long getLong(java.time.temporal.TemporalField);
+    method public java.time.Month getMonth();
+    method public int getMonthValue();
+    method public int getYear();
+    method public boolean isAfter(java.time.YearMonth);
+    method public boolean isBefore(java.time.YearMonth);
+    method public boolean isLeapYear();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
+    method public boolean isValidDay(int);
+    method public int lengthOfMonth();
+    method public int lengthOfYear();
+    method public java.time.YearMonth minusMonths(long);
+    method public java.time.YearMonth minusYears(long);
+    method public static java.time.YearMonth now();
+    method public static java.time.YearMonth now(java.time.ZoneId);
+    method public static java.time.YearMonth now(java.time.Clock);
+    method public static java.time.YearMonth of(int, java.time.Month);
+    method public static java.time.YearMonth of(int, int);
+    method public static java.time.YearMonth parse(java.lang.CharSequence);
+    method public static java.time.YearMonth parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.YearMonth plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.YearMonth plusMonths(long);
+    method public java.time.YearMonth plusYears(long);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.YearMonth with(java.time.temporal.TemporalField, long);
+    method public java.time.YearMonth withMonth(int);
+    method public java.time.YearMonth withYear(int);
+  }
+
+  public abstract class ZoneId implements java.io.Serializable {
+    method public static java.time.ZoneId from(java.time.temporal.TemporalAccessor);
+    method public static java.util.Set<java.lang.String> getAvailableZoneIds();
+    method public java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public abstract java.lang.String getId();
+    method public abstract java.time.zone.ZoneRules getRules();
+    method public java.time.ZoneId normalized();
+    method public static java.time.ZoneId of(java.lang.String, java.util.Map<java.lang.String, java.lang.String>);
+    method public static java.time.ZoneId of(java.lang.String);
+    method public static java.time.ZoneId ofOffset(java.lang.String, java.time.ZoneOffset);
+    method public static java.time.ZoneId systemDefault();
+    field public static final java.util.Map<java.lang.String, java.lang.String> SHORT_IDS;
+  }
+
+  public final class ZoneOffset extends java.time.ZoneId implements java.lang.Comparable java.io.Serializable java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public int compareTo(java.time.ZoneOffset);
+    method public static java.time.ZoneOffset from(java.time.temporal.TemporalAccessor);
+    method public int get(java.time.temporal.TemporalField);
+    method public java.lang.String getId();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public java.time.zone.ZoneRules getRules();
+    method public int getTotalSeconds();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public static java.time.ZoneOffset of(java.lang.String);
+    method public static java.time.ZoneOffset ofHours(int);
+    method public static java.time.ZoneOffset ofHoursMinutes(int, int);
+    method public static java.time.ZoneOffset ofHoursMinutesSeconds(int, int, int);
+    method public static java.time.ZoneOffset ofTotalSeconds(int);
+    method public <R> R query(java.time.temporal.TemporalQuery<R>);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    field public static final java.time.ZoneOffset MAX;
+    field public static final java.time.ZoneOffset MIN;
+    field public static final java.time.ZoneOffset UTC;
+  }
+
+  public final class ZonedDateTime implements java.time.chrono.ChronoZonedDateTime java.io.Serializable java.time.temporal.Temporal {
+    method public static java.time.ZonedDateTime from(java.time.temporal.TemporalAccessor);
+    method public int getDayOfMonth();
+    method public java.time.DayOfWeek getDayOfWeek();
+    method public int getDayOfYear();
+    method public int getHour();
+    method public int getMinute();
+    method public java.time.Month getMonth();
+    method public int getMonthValue();
+    method public int getNano();
+    method public java.time.ZoneOffset getOffset();
+    method public int getSecond();
+    method public int getYear();
+    method public java.time.ZoneId getZone();
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public java.time.ZonedDateTime minusDays(long);
+    method public java.time.ZonedDateTime minusHours(long);
+    method public java.time.ZonedDateTime minusMinutes(long);
+    method public java.time.ZonedDateTime minusMonths(long);
+    method public java.time.ZonedDateTime minusNanos(long);
+    method public java.time.ZonedDateTime minusSeconds(long);
+    method public java.time.ZonedDateTime minusWeeks(long);
+    method public java.time.ZonedDateTime minusYears(long);
+    method public static java.time.ZonedDateTime now();
+    method public static java.time.ZonedDateTime now(java.time.ZoneId);
+    method public static java.time.ZonedDateTime now(java.time.Clock);
+    method public static java.time.ZonedDateTime of(java.time.LocalDate, java.time.LocalTime, java.time.ZoneId);
+    method public static java.time.ZonedDateTime of(java.time.LocalDateTime, java.time.ZoneId);
+    method public static java.time.ZonedDateTime of(int, int, int, int, int, int, int, java.time.ZoneId);
+    method public static java.time.ZonedDateTime ofInstant(java.time.Instant, java.time.ZoneId);
+    method public static java.time.ZonedDateTime ofInstant(java.time.LocalDateTime, java.time.ZoneOffset, java.time.ZoneId);
+    method public static java.time.ZonedDateTime ofLocal(java.time.LocalDateTime, java.time.ZoneId, java.time.ZoneOffset);
+    method public static java.time.ZonedDateTime ofStrict(java.time.LocalDateTime, java.time.ZoneOffset, java.time.ZoneId);
+    method public static java.time.ZonedDateTime parse(java.lang.CharSequence);
+    method public static java.time.ZonedDateTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public java.time.ZonedDateTime plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.ZonedDateTime plusDays(long);
+    method public java.time.ZonedDateTime plusHours(long);
+    method public java.time.ZonedDateTime plusMinutes(long);
+    method public java.time.ZonedDateTime plusMonths(long);
+    method public java.time.ZonedDateTime plusNanos(long);
+    method public java.time.ZonedDateTime plusSeconds(long);
+    method public java.time.ZonedDateTime plusWeeks(long);
+    method public java.time.ZonedDateTime plusYears(long);
+    method public java.time.LocalDateTime toLocalDateTime();
+    method public java.time.OffsetDateTime toOffsetDateTime();
+    method public java.time.ZonedDateTime truncatedTo(java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.ZonedDateTime with(java.time.temporal.TemporalField, long);
+    method public java.time.ZonedDateTime withDayOfMonth(int);
+    method public java.time.ZonedDateTime withDayOfYear(int);
+    method public java.time.ZonedDateTime withEarlierOffsetAtOverlap();
+    method public java.time.ZonedDateTime withFixedOffsetZone();
+    method public java.time.ZonedDateTime withHour(int);
+    method public java.time.ZonedDateTime withLaterOffsetAtOverlap();
+    method public java.time.ZonedDateTime withMinute(int);
+    method public java.time.ZonedDateTime withMonth(int);
+    method public java.time.ZonedDateTime withNano(int);
+    method public java.time.ZonedDateTime withSecond(int);
+    method public java.time.ZonedDateTime withYear(int);
+    method public java.time.ZonedDateTime withZoneSameInstant(java.time.ZoneId);
+    method public java.time.ZonedDateTime withZoneSameLocal(java.time.ZoneId);
+  }
+
+}
+
+package java.time.chrono {
+
+  public abstract class AbstractChronology implements java.time.chrono.Chronology {
+    ctor protected AbstractChronology();
+    method public int compareTo(java.time.chrono.Chronology);
+    method public java.time.chrono.ChronoLocalDate resolveDate(java.util.Map<java.time.temporal.TemporalField, java.lang.Long>, java.time.format.ResolverStyle);
+  }
+
+  public abstract interface ChronoLocalDate implements java.lang.Comparable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public default java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public default java.time.chrono.ChronoLocalDateTime<?> atTime(java.time.LocalTime);
+    method public default int compareTo(java.time.chrono.ChronoLocalDate);
+    method public abstract boolean equals(java.lang.Object);
+    method public default java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.chrono.ChronoLocalDate from(java.time.temporal.TemporalAccessor);
+    method public abstract java.time.chrono.Chronology getChronology();
+    method public default java.time.chrono.Era getEra();
+    method public abstract int hashCode();
+    method public default boolean isAfter(java.time.chrono.ChronoLocalDate);
+    method public default boolean isBefore(java.time.chrono.ChronoLocalDate);
+    method public default boolean isEqual(java.time.chrono.ChronoLocalDate);
+    method public default boolean isLeapYear();
+    method public default boolean isSupported(java.time.temporal.TemporalField);
+    method public default boolean isSupported(java.time.temporal.TemporalUnit);
+    method public abstract int lengthOfMonth();
+    method public default int lengthOfYear();
+    method public default java.time.chrono.ChronoLocalDate plus(long, java.time.temporal.TemporalUnit);
+    method public static java.util.Comparator<java.time.chrono.ChronoLocalDate> timeLineOrder();
+    method public default long toEpochDay();
+    method public abstract java.lang.String toString();
+    method public abstract long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public abstract java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+    method public default java.time.chrono.ChronoLocalDate with(java.time.temporal.TemporalField, long);
+  }
+
+   abstract class ChronoLocalDateImpl<D extends java.time.chrono.ChronoLocalDate> implements java.time.chrono.ChronoLocalDate java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+  }
+
+  public abstract interface ChronoLocalDateTime<D extends java.time.chrono.ChronoLocalDate> implements java.lang.Comparable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+    method public default java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> atZone(java.time.ZoneId);
+    method public default int compareTo(java.time.chrono.ChronoLocalDateTime<?>);
+    method public abstract boolean equals(java.lang.Object);
+    method public default java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.chrono.ChronoLocalDateTime<?> from(java.time.temporal.TemporalAccessor);
+    method public default java.time.chrono.Chronology getChronology();
+    method public abstract int hashCode();
+    method public default boolean isAfter(java.time.chrono.ChronoLocalDateTime<?>);
+    method public default boolean isBefore(java.time.chrono.ChronoLocalDateTime<?>);
+    method public default boolean isEqual(java.time.chrono.ChronoLocalDateTime<?>);
+    method public abstract boolean isSupported(java.time.temporal.TemporalField);
+    method public default boolean isSupported(java.time.temporal.TemporalUnit);
+    method public abstract java.time.chrono.ChronoLocalDateTime<D> plus(long, java.time.temporal.TemporalUnit);
+    method public static java.util.Comparator<java.time.chrono.ChronoLocalDateTime<?>> timeLineOrder();
+    method public default long toEpochSecond(java.time.ZoneOffset);
+    method public default java.time.Instant toInstant(java.time.ZoneOffset);
+    method public abstract D toLocalDate();
+    method public abstract java.time.LocalTime toLocalTime();
+    method public abstract java.lang.String toString();
+    method public abstract java.time.chrono.ChronoLocalDateTime<D> with(java.time.temporal.TemporalField, long);
+  }
+
+  public abstract interface ChronoPeriod implements java.time.temporal.TemporalAmount {
+    method public abstract java.time.temporal.Temporal addTo(java.time.temporal.Temporal);
+    method public static java.time.chrono.ChronoPeriod between(java.time.chrono.ChronoLocalDate, java.time.chrono.ChronoLocalDate);
+    method public abstract boolean equals(java.lang.Object);
+    method public abstract long get(java.time.temporal.TemporalUnit);
+    method public abstract java.time.chrono.Chronology getChronology();
+    method public abstract java.util.List<java.time.temporal.TemporalUnit> getUnits();
+    method public abstract int hashCode();
+    method public default boolean isNegative();
+    method public default boolean isZero();
+    method public abstract java.time.chrono.ChronoPeriod minus(java.time.temporal.TemporalAmount);
+    method public abstract java.time.chrono.ChronoPeriod multipliedBy(int);
+    method public default java.time.chrono.ChronoPeriod negated();
+    method public abstract java.time.chrono.ChronoPeriod normalized();
+    method public abstract java.time.chrono.ChronoPeriod plus(java.time.temporal.TemporalAmount);
+    method public abstract java.time.temporal.Temporal subtractFrom(java.time.temporal.Temporal);
+    method public abstract java.lang.String toString();
+  }
+
+  public abstract interface ChronoZonedDateTime<D extends java.time.chrono.ChronoLocalDate> implements java.lang.Comparable java.time.temporal.Temporal {
+    method public default int compareTo(java.time.chrono.ChronoZonedDateTime<?>);
+    method public abstract boolean equals(java.lang.Object);
+    method public default java.lang.String format(java.time.format.DateTimeFormatter);
+    method public static java.time.chrono.ChronoZonedDateTime<?> from(java.time.temporal.TemporalAccessor);
+    method public default java.time.chrono.Chronology getChronology();
+    method public default long getLong(java.time.temporal.TemporalField);
+    method public abstract java.time.ZoneOffset getOffset();
+    method public abstract java.time.ZoneId getZone();
+    method public abstract int hashCode();
+    method public default boolean isAfter(java.time.chrono.ChronoZonedDateTime<?>);
+    method public default boolean isBefore(java.time.chrono.ChronoZonedDateTime<?>);
+    method public default boolean isEqual(java.time.chrono.ChronoZonedDateTime<?>);
+    method public abstract boolean isSupported(java.time.temporal.TemporalField);
+    method public default boolean isSupported(java.time.temporal.TemporalUnit);
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> plus(long, java.time.temporal.TemporalUnit);
+    method public static java.util.Comparator<java.time.chrono.ChronoZonedDateTime<?>> timeLineOrder();
+    method public default long toEpochSecond();
+    method public default java.time.Instant toInstant();
+    method public default D toLocalDate();
+    method public abstract java.time.chrono.ChronoLocalDateTime<D> toLocalDateTime();
+    method public default java.time.LocalTime toLocalTime();
+    method public abstract java.lang.String toString();
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> with(java.time.temporal.TemporalField, long);
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> withEarlierOffsetAtOverlap();
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> withLaterOffsetAtOverlap();
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> withZoneSameInstant(java.time.ZoneId);
+    method public abstract java.time.chrono.ChronoZonedDateTime<D> withZoneSameLocal(java.time.ZoneId);
+  }
+
+  public abstract interface Chronology implements java.lang.Comparable {
+    method public abstract int compareTo(java.time.chrono.Chronology);
+    method public default java.time.chrono.ChronoLocalDate date(java.time.chrono.Era, int, int, int);
+    method public abstract java.time.chrono.ChronoLocalDate date(int, int, int);
+    method public abstract java.time.chrono.ChronoLocalDate date(java.time.temporal.TemporalAccessor);
+    method public abstract java.time.chrono.ChronoLocalDate dateEpochDay(long);
+    method public default java.time.chrono.ChronoLocalDate dateNow();
+    method public default java.time.chrono.ChronoLocalDate dateNow(java.time.ZoneId);
+    method public default java.time.chrono.ChronoLocalDate dateNow(java.time.Clock);
+    method public default java.time.chrono.ChronoLocalDate dateYearDay(java.time.chrono.Era, int, int);
+    method public abstract java.time.chrono.ChronoLocalDate dateYearDay(int, int);
+    method public abstract boolean equals(java.lang.Object);
+    method public abstract java.time.chrono.Era eraOf(int);
+    method public abstract java.util.List<java.time.chrono.Era> eras();
+    method public static java.time.chrono.Chronology from(java.time.temporal.TemporalAccessor);
+    method public static java.util.Set<java.time.chrono.Chronology> getAvailableChronologies();
+    method public abstract java.lang.String getCalendarType();
+    method public default java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public abstract java.lang.String getId();
+    method public abstract int hashCode();
+    method public abstract boolean isLeapYear(long);
+    method public default java.time.chrono.ChronoLocalDateTime<? extends java.time.chrono.ChronoLocalDate> localDateTime(java.time.temporal.TemporalAccessor);
+    method public static java.time.chrono.Chronology of(java.lang.String);
+    method public static java.time.chrono.Chronology ofLocale(java.util.Locale);
+    method public default java.time.chrono.ChronoPeriod period(int, int, int);
+    method public abstract int prolepticYear(java.time.chrono.Era, int);
+    method public abstract java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public abstract java.time.chrono.ChronoLocalDate resolveDate(java.util.Map<java.time.temporal.TemporalField, java.lang.Long>, java.time.format.ResolverStyle);
+    method public abstract java.lang.String toString();
+    method public default java.time.chrono.ChronoZonedDateTime<? extends java.time.chrono.ChronoLocalDate> zonedDateTime(java.time.temporal.TemporalAccessor);
+    method public default java.time.chrono.ChronoZonedDateTime<? extends java.time.chrono.ChronoLocalDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
+  }
+
+  public abstract interface Era implements java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+    method public default java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+    method public default java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public default long getLong(java.time.temporal.TemporalField);
+    method public abstract int getValue();
+    method public default boolean isSupported(java.time.temporal.TemporalField);
+  }
+
+  public final class HijrahChronology extends java.time.chrono.AbstractChronology implements java.io.Serializable {
+    method public java.time.chrono.HijrahDate date(java.time.chrono.Era, int, int, int);
+    method public java.time.chrono.HijrahDate date(int, int, int);
+    method public java.time.chrono.HijrahDate date(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.HijrahDate dateEpochDay(long);
+    method public java.time.chrono.HijrahDate dateNow();
+    method public java.time.chrono.HijrahDate dateNow(java.time.ZoneId);
+    method public java.time.chrono.HijrahDate dateNow(java.time.Clock);
+    method public java.time.chrono.HijrahDate dateYearDay(java.time.chrono.Era, int, int);
+    method public java.time.chrono.HijrahDate dateYearDay(int, int);
+    method public java.time.chrono.HijrahEra eraOf(int);
+    method public java.util.List<java.time.chrono.Era> eras();
+    method public java.lang.String getCalendarType();
+    method public java.lang.String getId();
+    method public boolean isLeapYear(long);
+    method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.HijrahDate> localDateTime(java.time.temporal.TemporalAccessor);
+    method public int prolepticYear(java.time.chrono.Era, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.HijrahDate> zonedDateTime(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.HijrahDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
+    field public static final java.time.chrono.HijrahChronology INSTANCE;
+  }
+
+  public final class HijrahDate extends java.time.chrono.ChronoLocalDateImpl implements java.time.chrono.ChronoLocalDate java.io.Serializable {
+    method public final java.time.chrono.ChronoLocalDateTime<java.time.chrono.HijrahDate> atTime(java.time.LocalTime);
+    method public static java.time.chrono.HijrahDate from(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.HijrahChronology getChronology();
+    method public java.time.chrono.HijrahEra getEra();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public boolean isLeapYear();
+    method public int lengthOfMonth();
+    method public int lengthOfYear();
+    method public static java.time.chrono.HijrahDate now();
+    method public static java.time.chrono.HijrahDate now(java.time.ZoneId);
+    method public static java.time.chrono.HijrahDate now(java.time.Clock);
+    method public static java.time.chrono.HijrahDate of(int, int, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public long toEpochDay();
+    method public java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+    method public java.time.chrono.HijrahDate withVariant(java.time.chrono.HijrahChronology);
+  }
+
+  public final class HijrahEra extends java.lang.Enum implements java.time.chrono.Era {
+    method public int getValue();
+    method public static java.time.chrono.HijrahEra of(int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public static java.time.chrono.HijrahEra valueOf(java.lang.String);
+    method public static final java.time.chrono.HijrahEra[] values();
+    enum_constant public static final java.time.chrono.HijrahEra AH;
+  }
+
+  public final class IsoChronology extends java.time.chrono.AbstractChronology implements java.io.Serializable {
+    method public java.time.LocalDate date(java.time.chrono.Era, int, int, int);
+    method public java.time.LocalDate date(int, int, int);
+    method public java.time.LocalDate date(java.time.temporal.TemporalAccessor);
+    method public java.time.LocalDate dateEpochDay(long);
+    method public java.time.LocalDate dateNow();
+    method public java.time.LocalDate dateNow(java.time.ZoneId);
+    method public java.time.LocalDate dateNow(java.time.Clock);
+    method public java.time.LocalDate dateYearDay(java.time.chrono.Era, int, int);
+    method public java.time.LocalDate dateYearDay(int, int);
+    method public java.time.chrono.IsoEra eraOf(int);
+    method public java.util.List<java.time.chrono.Era> eras();
+    method public java.lang.String getCalendarType();
+    method public java.lang.String getId();
+    method public boolean isLeapYear(long);
+    method public java.time.LocalDateTime localDateTime(java.time.temporal.TemporalAccessor);
+    method public java.time.Period period(int, int, int);
+    method public int prolepticYear(java.time.chrono.Era, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public java.time.ZonedDateTime zonedDateTime(java.time.temporal.TemporalAccessor);
+    method public java.time.ZonedDateTime zonedDateTime(java.time.Instant, java.time.ZoneId);
+    field public static final java.time.chrono.IsoChronology INSTANCE;
+  }
+
+  public final class IsoEra extends java.lang.Enum implements java.time.chrono.Era {
+    method public int getValue();
+    method public static java.time.chrono.IsoEra of(int);
+    method public static java.time.chrono.IsoEra valueOf(java.lang.String);
+    method public static final java.time.chrono.IsoEra[] values();
+    enum_constant public static final java.time.chrono.IsoEra BCE;
+    enum_constant public static final java.time.chrono.IsoEra CE;
+  }
+
+  public final class JapaneseChronology extends java.time.chrono.AbstractChronology implements java.io.Serializable {
+    method public java.time.chrono.JapaneseDate date(java.time.chrono.Era, int, int, int);
+    method public java.time.chrono.JapaneseDate date(int, int, int);
+    method public java.time.chrono.JapaneseDate date(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.JapaneseDate dateEpochDay(long);
+    method public java.time.chrono.JapaneseDate dateNow();
+    method public java.time.chrono.JapaneseDate dateNow(java.time.ZoneId);
+    method public java.time.chrono.JapaneseDate dateNow(java.time.Clock);
+    method public java.time.chrono.JapaneseDate dateYearDay(java.time.chrono.Era, int, int);
+    method public java.time.chrono.JapaneseDate dateYearDay(int, int);
+    method public java.time.chrono.JapaneseEra eraOf(int);
+    method public java.util.List<java.time.chrono.Era> eras();
+    method public java.lang.String getCalendarType();
+    method public java.lang.String getId();
+    method public boolean isLeapYear(long);
+    method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.JapaneseDate> localDateTime(java.time.temporal.TemporalAccessor);
+    method public int prolepticYear(java.time.chrono.Era, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.JapaneseDate> zonedDateTime(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.JapaneseDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
+    field public static final java.time.chrono.JapaneseChronology INSTANCE;
+  }
+
+  public final class JapaneseDate extends java.time.chrono.ChronoLocalDateImpl implements java.time.chrono.ChronoLocalDate java.io.Serializable {
+    method public final java.time.chrono.ChronoLocalDateTime<java.time.chrono.JapaneseDate> atTime(java.time.LocalTime);
+    method public static java.time.chrono.JapaneseDate from(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.JapaneseChronology getChronology();
+    method public java.time.chrono.JapaneseEra getEra();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalField);
+    method public int lengthOfMonth();
+    method public int lengthOfYear();
+    method public static java.time.chrono.JapaneseDate now();
+    method public static java.time.chrono.JapaneseDate now(java.time.ZoneId);
+    method public static java.time.chrono.JapaneseDate now(java.time.Clock);
+    method public static java.time.chrono.JapaneseDate of(java.time.chrono.JapaneseEra, int, int, int);
+    method public static java.time.chrono.JapaneseDate of(int, int, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public long toEpochDay();
+    method public java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+  }
+
+  public final class JapaneseEra implements java.time.chrono.Era java.io.Serializable {
+    method public int getValue();
+    method public static java.time.chrono.JapaneseEra of(int);
+    method public static java.time.chrono.JapaneseEra valueOf(java.lang.String);
+    method public static java.time.chrono.JapaneseEra[] values();
+    field public static final java.time.chrono.JapaneseEra HEISEI;
+    field public static final java.time.chrono.JapaneseEra MEIJI;
+    field public static final java.time.chrono.JapaneseEra SHOWA;
+    field public static final java.time.chrono.JapaneseEra TAISHO;
+  }
+
+  public final class MinguoChronology extends java.time.chrono.AbstractChronology implements java.io.Serializable {
+    method public java.time.chrono.MinguoDate date(java.time.chrono.Era, int, int, int);
+    method public java.time.chrono.MinguoDate date(int, int, int);
+    method public java.time.chrono.MinguoDate date(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.MinguoDate dateEpochDay(long);
+    method public java.time.chrono.MinguoDate dateNow();
+    method public java.time.chrono.MinguoDate dateNow(java.time.ZoneId);
+    method public java.time.chrono.MinguoDate dateNow(java.time.Clock);
+    method public java.time.chrono.MinguoDate dateYearDay(java.time.chrono.Era, int, int);
+    method public java.time.chrono.MinguoDate dateYearDay(int, int);
+    method public java.time.chrono.MinguoEra eraOf(int);
+    method public java.util.List<java.time.chrono.Era> eras();
+    method public java.lang.String getCalendarType();
+    method public java.lang.String getId();
+    method public boolean isLeapYear(long);
+    method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.MinguoDate> localDateTime(java.time.temporal.TemporalAccessor);
+    method public int prolepticYear(java.time.chrono.Era, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.MinguoDate> zonedDateTime(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.MinguoDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
+    field public static final java.time.chrono.MinguoChronology INSTANCE;
+  }
+
+  public final class MinguoDate extends java.time.chrono.ChronoLocalDateImpl implements java.time.chrono.ChronoLocalDate java.io.Serializable {
+    method public final java.time.chrono.ChronoLocalDateTime<java.time.chrono.MinguoDate> atTime(java.time.LocalTime);
+    method public static java.time.chrono.MinguoDate from(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.MinguoChronology getChronology();
+    method public java.time.chrono.MinguoEra getEra();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int lengthOfMonth();
+    method public static java.time.chrono.MinguoDate now();
+    method public static java.time.chrono.MinguoDate now(java.time.ZoneId);
+    method public static java.time.chrono.MinguoDate now(java.time.Clock);
+    method public static java.time.chrono.MinguoDate of(int, int, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public long toEpochDay();
+    method public java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+  }
+
+  public final class MinguoEra extends java.lang.Enum implements java.time.chrono.Era {
+    method public int getValue();
+    method public static java.time.chrono.MinguoEra of(int);
+    method public static java.time.chrono.MinguoEra valueOf(java.lang.String);
+    method public static final java.time.chrono.MinguoEra[] values();
+    enum_constant public static final java.time.chrono.MinguoEra BEFORE_ROC;
+    enum_constant public static final java.time.chrono.MinguoEra ROC;
+  }
+
+  public final class ThaiBuddhistChronology extends java.time.chrono.AbstractChronology implements java.io.Serializable {
+    method public java.time.chrono.ThaiBuddhistDate date(java.time.chrono.Era, int, int, int);
+    method public java.time.chrono.ThaiBuddhistDate date(int, int, int);
+    method public java.time.chrono.ThaiBuddhistDate date(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ThaiBuddhistDate dateEpochDay(long);
+    method public java.time.chrono.ThaiBuddhistDate dateNow();
+    method public java.time.chrono.ThaiBuddhistDate dateNow(java.time.ZoneId);
+    method public java.time.chrono.ThaiBuddhistDate dateNow(java.time.Clock);
+    method public java.time.chrono.ThaiBuddhistDate dateYearDay(java.time.chrono.Era, int, int);
+    method public java.time.chrono.ThaiBuddhistDate dateYearDay(int, int);
+    method public java.time.chrono.ThaiBuddhistEra eraOf(int);
+    method public java.util.List<java.time.chrono.Era> eras();
+    method public java.lang.String getCalendarType();
+    method public java.lang.String getId();
+    method public boolean isLeapYear(long);
+    method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.ThaiBuddhistDate> localDateTime(java.time.temporal.TemporalAccessor);
+    method public int prolepticYear(java.time.chrono.Era, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.ThaiBuddhistDate> zonedDateTime(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.ThaiBuddhistDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
+    field public static final java.time.chrono.ThaiBuddhistChronology INSTANCE;
+  }
+
+  public final class ThaiBuddhistDate extends java.time.chrono.ChronoLocalDateImpl implements java.time.chrono.ChronoLocalDate java.io.Serializable {
+    method public final java.time.chrono.ChronoLocalDateTime<java.time.chrono.ThaiBuddhistDate> atTime(java.time.LocalTime);
+    method public static java.time.chrono.ThaiBuddhistDate from(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ThaiBuddhistChronology getChronology();
+    method public java.time.chrono.ThaiBuddhistEra getEra();
+    method public long getLong(java.time.temporal.TemporalField);
+    method public int lengthOfMonth();
+    method public static java.time.chrono.ThaiBuddhistDate now();
+    method public static java.time.chrono.ThaiBuddhistDate now(java.time.ZoneId);
+    method public static java.time.chrono.ThaiBuddhistDate now(java.time.Clock);
+    method public static java.time.chrono.ThaiBuddhistDate of(int, int, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+    method public long toEpochDay();
+    method public java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+  }
+
+  public final class ThaiBuddhistEra extends java.lang.Enum implements java.time.chrono.Era {
+    method public int getValue();
+    method public static java.time.chrono.ThaiBuddhistEra of(int);
+    method public static java.time.chrono.ThaiBuddhistEra valueOf(java.lang.String);
+    method public static final java.time.chrono.ThaiBuddhistEra[] values();
+    enum_constant public static final java.time.chrono.ThaiBuddhistEra BE;
+    enum_constant public static final java.time.chrono.ThaiBuddhistEra BEFORE_BE;
+  }
+
+}
+
+package java.time.format {
+
+  public final class DateTimeFormatter {
+    method public java.lang.String format(java.time.temporal.TemporalAccessor);
+    method public void formatTo(java.time.temporal.TemporalAccessor, java.lang.Appendable);
+    method public java.time.chrono.Chronology getChronology();
+    method public java.time.format.DecimalStyle getDecimalStyle();
+    method public java.util.Locale getLocale();
+    method public java.util.Set<java.time.temporal.TemporalField> getResolverFields();
+    method public java.time.format.ResolverStyle getResolverStyle();
+    method public java.time.ZoneId getZone();
+    method public static java.time.format.DateTimeFormatter ofLocalizedDate(java.time.format.FormatStyle);
+    method public static java.time.format.DateTimeFormatter ofLocalizedDateTime(java.time.format.FormatStyle);
+    method public static java.time.format.DateTimeFormatter ofLocalizedDateTime(java.time.format.FormatStyle, java.time.format.FormatStyle);
+    method public static java.time.format.DateTimeFormatter ofLocalizedTime(java.time.format.FormatStyle);
+    method public static java.time.format.DateTimeFormatter ofPattern(java.lang.String);
+    method public static java.time.format.DateTimeFormatter ofPattern(java.lang.String, java.util.Locale);
+    method public java.time.temporal.TemporalAccessor parse(java.lang.CharSequence);
+    method public java.time.temporal.TemporalAccessor parse(java.lang.CharSequence, java.text.ParsePosition);
+    method public <T> T parse(java.lang.CharSequence, java.time.temporal.TemporalQuery<T>);
+    method public java.time.temporal.TemporalAccessor parseBest(java.lang.CharSequence, java.time.temporal.TemporalQuery<?>...);
+    method public java.time.temporal.TemporalAccessor parseUnresolved(java.lang.CharSequence, java.text.ParsePosition);
+    method public static final java.time.temporal.TemporalQuery<java.time.Period> parsedExcessDays();
+    method public static final java.time.temporal.TemporalQuery<java.lang.Boolean> parsedLeapSecond();
+    method public java.text.Format toFormat();
+    method public java.text.Format toFormat(java.time.temporal.TemporalQuery<?>);
+    method public java.time.format.DateTimeFormatter withChronology(java.time.chrono.Chronology);
+    method public java.time.format.DateTimeFormatter withDecimalStyle(java.time.format.DecimalStyle);
+    method public java.time.format.DateTimeFormatter withLocale(java.util.Locale);
+    method public java.time.format.DateTimeFormatter withResolverFields(java.time.temporal.TemporalField...);
+    method public java.time.format.DateTimeFormatter withResolverFields(java.util.Set<java.time.temporal.TemporalField>);
+    method public java.time.format.DateTimeFormatter withResolverStyle(java.time.format.ResolverStyle);
+    method public java.time.format.DateTimeFormatter withZone(java.time.ZoneId);
+    field public static final java.time.format.DateTimeFormatter BASIC_ISO_DATE;
+    field public static final java.time.format.DateTimeFormatter ISO_DATE;
+    field public static final java.time.format.DateTimeFormatter ISO_DATE_TIME;
+    field public static final java.time.format.DateTimeFormatter ISO_INSTANT;
+    field public static final java.time.format.DateTimeFormatter ISO_LOCAL_DATE;
+    field public static final java.time.format.DateTimeFormatter ISO_LOCAL_DATE_TIME;
+    field public static final java.time.format.DateTimeFormatter ISO_LOCAL_TIME;
+    field public static final java.time.format.DateTimeFormatter ISO_OFFSET_DATE;
+    field public static final java.time.format.DateTimeFormatter ISO_OFFSET_DATE_TIME;
+    field public static final java.time.format.DateTimeFormatter ISO_OFFSET_TIME;
+    field public static final java.time.format.DateTimeFormatter ISO_ORDINAL_DATE;
+    field public static final java.time.format.DateTimeFormatter ISO_TIME;
+    field public static final java.time.format.DateTimeFormatter ISO_WEEK_DATE;
+    field public static final java.time.format.DateTimeFormatter ISO_ZONED_DATE_TIME;
+    field public static final java.time.format.DateTimeFormatter RFC_1123_DATE_TIME;
+  }
+
+  public final class DateTimeFormatterBuilder {
+    ctor public DateTimeFormatterBuilder();
+    method public java.time.format.DateTimeFormatterBuilder append(java.time.format.DateTimeFormatter);
+    method public java.time.format.DateTimeFormatterBuilder appendChronologyId();
+    method public java.time.format.DateTimeFormatterBuilder appendChronologyText(java.time.format.TextStyle);
+    method public java.time.format.DateTimeFormatterBuilder appendFraction(java.time.temporal.TemporalField, int, int, boolean);
+    method public java.time.format.DateTimeFormatterBuilder appendInstant();
+    method public java.time.format.DateTimeFormatterBuilder appendInstant(int);
+    method public java.time.format.DateTimeFormatterBuilder appendLiteral(char);
+    method public java.time.format.DateTimeFormatterBuilder appendLiteral(java.lang.String);
+    method public java.time.format.DateTimeFormatterBuilder appendLocalized(java.time.format.FormatStyle, java.time.format.FormatStyle);
+    method public java.time.format.DateTimeFormatterBuilder appendLocalizedOffset(java.time.format.TextStyle);
+    method public java.time.format.DateTimeFormatterBuilder appendOffset(java.lang.String, java.lang.String);
+    method public java.time.format.DateTimeFormatterBuilder appendOffsetId();
+    method public java.time.format.DateTimeFormatterBuilder appendOptional(java.time.format.DateTimeFormatter);
+    method public java.time.format.DateTimeFormatterBuilder appendPattern(java.lang.String);
+    method public java.time.format.DateTimeFormatterBuilder appendText(java.time.temporal.TemporalField);
+    method public java.time.format.DateTimeFormatterBuilder appendText(java.time.temporal.TemporalField, java.time.format.TextStyle);
+    method public java.time.format.DateTimeFormatterBuilder appendText(java.time.temporal.TemporalField, java.util.Map<java.lang.Long, java.lang.String>);
+    method public java.time.format.DateTimeFormatterBuilder appendValue(java.time.temporal.TemporalField);
+    method public java.time.format.DateTimeFormatterBuilder appendValue(java.time.temporal.TemporalField, int);
+    method public java.time.format.DateTimeFormatterBuilder appendValue(java.time.temporal.TemporalField, int, int, java.time.format.SignStyle);
+    method public java.time.format.DateTimeFormatterBuilder appendValueReduced(java.time.temporal.TemporalField, int, int, int);
+    method public java.time.format.DateTimeFormatterBuilder appendValueReduced(java.time.temporal.TemporalField, int, int, java.time.chrono.ChronoLocalDate);
+    method public java.time.format.DateTimeFormatterBuilder appendZoneId();
+    method public java.time.format.DateTimeFormatterBuilder appendZoneOrOffsetId();
+    method public java.time.format.DateTimeFormatterBuilder appendZoneRegionId();
+    method public java.time.format.DateTimeFormatterBuilder appendZoneText(java.time.format.TextStyle);
+    method public java.time.format.DateTimeFormatterBuilder appendZoneText(java.time.format.TextStyle, java.util.Set<java.time.ZoneId>);
+    method public static java.lang.String getLocalizedDateTimePattern(java.time.format.FormatStyle, java.time.format.FormatStyle, java.time.chrono.Chronology, java.util.Locale);
+    method public java.time.format.DateTimeFormatterBuilder optionalEnd();
+    method public java.time.format.DateTimeFormatterBuilder optionalStart();
+    method public java.time.format.DateTimeFormatterBuilder padNext(int);
+    method public java.time.format.DateTimeFormatterBuilder padNext(int, char);
+    method public java.time.format.DateTimeFormatterBuilder parseCaseInsensitive();
+    method public java.time.format.DateTimeFormatterBuilder parseCaseSensitive();
+    method public java.time.format.DateTimeFormatterBuilder parseDefaulting(java.time.temporal.TemporalField, long);
+    method public java.time.format.DateTimeFormatterBuilder parseLenient();
+    method public java.time.format.DateTimeFormatterBuilder parseStrict();
+    method public java.time.format.DateTimeFormatter toFormatter();
+    method public java.time.format.DateTimeFormatter toFormatter(java.util.Locale);
+  }
+
+  public class DateTimeParseException extends java.time.DateTimeException {
+    ctor public DateTimeParseException(java.lang.String, java.lang.CharSequence, int);
+    ctor public DateTimeParseException(java.lang.String, java.lang.CharSequence, int, java.lang.Throwable);
+    method public int getErrorIndex();
+    method public java.lang.String getParsedString();
+  }
+
+  public final class DecimalStyle {
+    method public static java.util.Set<java.util.Locale> getAvailableLocales();
+    method public char getDecimalSeparator();
+    method public char getNegativeSign();
+    method public char getPositiveSign();
+    method public char getZeroDigit();
+    method public static java.time.format.DecimalStyle of(java.util.Locale);
+    method public static java.time.format.DecimalStyle ofDefaultLocale();
+    method public java.time.format.DecimalStyle withDecimalSeparator(char);
+    method public java.time.format.DecimalStyle withNegativeSign(char);
+    method public java.time.format.DecimalStyle withPositiveSign(char);
+    method public java.time.format.DecimalStyle withZeroDigit(char);
+    field public static final java.time.format.DecimalStyle STANDARD;
+  }
+
+  public final class FormatStyle extends java.lang.Enum {
+    method public static java.time.format.FormatStyle valueOf(java.lang.String);
+    method public static final java.time.format.FormatStyle[] values();
+    enum_constant public static final java.time.format.FormatStyle FULL;
+    enum_constant public static final java.time.format.FormatStyle LONG;
+    enum_constant public static final java.time.format.FormatStyle MEDIUM;
+    enum_constant public static final java.time.format.FormatStyle SHORT;
+  }
+
+  public final class ResolverStyle extends java.lang.Enum {
+    method public static java.time.format.ResolverStyle valueOf(java.lang.String);
+    method public static final java.time.format.ResolverStyle[] values();
+    enum_constant public static final java.time.format.ResolverStyle LENIENT;
+    enum_constant public static final java.time.format.ResolverStyle SMART;
+    enum_constant public static final java.time.format.ResolverStyle STRICT;
+  }
+
+  public final class SignStyle extends java.lang.Enum {
+    method public static java.time.format.SignStyle valueOf(java.lang.String);
+    method public static final java.time.format.SignStyle[] values();
+    enum_constant public static final java.time.format.SignStyle ALWAYS;
+    enum_constant public static final java.time.format.SignStyle EXCEEDS_PAD;
+    enum_constant public static final java.time.format.SignStyle NEVER;
+    enum_constant public static final java.time.format.SignStyle NORMAL;
+    enum_constant public static final java.time.format.SignStyle NOT_NEGATIVE;
+  }
+
+  public final class TextStyle extends java.lang.Enum {
+    method public java.time.format.TextStyle asNormal();
+    method public java.time.format.TextStyle asStandalone();
+    method public boolean isStandalone();
+    method public static java.time.format.TextStyle valueOf(java.lang.String);
+    method public static final java.time.format.TextStyle[] values();
+    enum_constant public static final java.time.format.TextStyle FULL;
+    enum_constant public static final java.time.format.TextStyle FULL_STANDALONE;
+    enum_constant public static final java.time.format.TextStyle NARROW;
+    enum_constant public static final java.time.format.TextStyle NARROW_STANDALONE;
+    enum_constant public static final java.time.format.TextStyle SHORT;
+    enum_constant public static final java.time.format.TextStyle SHORT_STANDALONE;
+  }
+
+}
+
+package java.time.temporal {
+
+  public final class ChronoField extends java.lang.Enum implements java.time.temporal.TemporalField {
+    method public <R extends java.time.temporal.Temporal> R adjustInto(R, long);
+    method public int checkValidIntValue(long);
+    method public long checkValidValue(long);
+    method public java.time.temporal.TemporalUnit getBaseUnit();
+    method public java.lang.String getDisplayName(java.util.Locale);
+    method public long getFrom(java.time.temporal.TemporalAccessor);
+    method public java.time.temporal.TemporalUnit getRangeUnit();
+    method public boolean isDateBased();
+    method public boolean isSupportedBy(java.time.temporal.TemporalAccessor);
+    method public boolean isTimeBased();
+    method public java.time.temporal.ValueRange range();
+    method public java.time.temporal.ValueRange rangeRefinedBy(java.time.temporal.TemporalAccessor);
+    method public static java.time.temporal.ChronoField valueOf(java.lang.String);
+    method public static final java.time.temporal.ChronoField[] values();
+    enum_constant public static final java.time.temporal.ChronoField ALIGNED_DAY_OF_WEEK_IN_MONTH;
+    enum_constant public static final java.time.temporal.ChronoField ALIGNED_DAY_OF_WEEK_IN_YEAR;
+    enum_constant public static final java.time.temporal.ChronoField ALIGNED_WEEK_OF_MONTH;
+    enum_constant public static final java.time.temporal.ChronoField ALIGNED_WEEK_OF_YEAR;
+    enum_constant public static final java.time.temporal.ChronoField AMPM_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField CLOCK_HOUR_OF_AMPM;
+    enum_constant public static final java.time.temporal.ChronoField CLOCK_HOUR_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField DAY_OF_MONTH;
+    enum_constant public static final java.time.temporal.ChronoField DAY_OF_WEEK;
+    enum_constant public static final java.time.temporal.ChronoField DAY_OF_YEAR;
+    enum_constant public static final java.time.temporal.ChronoField EPOCH_DAY;
+    enum_constant public static final java.time.temporal.ChronoField ERA;
+    enum_constant public static final java.time.temporal.ChronoField HOUR_OF_AMPM;
+    enum_constant public static final java.time.temporal.ChronoField HOUR_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField INSTANT_SECONDS;
+    enum_constant public static final java.time.temporal.ChronoField MICRO_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField MICRO_OF_SECOND;
+    enum_constant public static final java.time.temporal.ChronoField MILLI_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField MILLI_OF_SECOND;
+    enum_constant public static final java.time.temporal.ChronoField MINUTE_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField MINUTE_OF_HOUR;
+    enum_constant public static final java.time.temporal.ChronoField MONTH_OF_YEAR;
+    enum_constant public static final java.time.temporal.ChronoField NANO_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField NANO_OF_SECOND;
+    enum_constant public static final java.time.temporal.ChronoField OFFSET_SECONDS;
+    enum_constant public static final java.time.temporal.ChronoField PROLEPTIC_MONTH;
+    enum_constant public static final java.time.temporal.ChronoField SECOND_OF_DAY;
+    enum_constant public static final java.time.temporal.ChronoField SECOND_OF_MINUTE;
+    enum_constant public static final java.time.temporal.ChronoField YEAR;
+    enum_constant public static final java.time.temporal.ChronoField YEAR_OF_ERA;
+  }
+
+  public final class ChronoUnit extends java.lang.Enum implements java.time.temporal.TemporalUnit {
+    method public <R extends java.time.temporal.Temporal> R addTo(R, long);
+    method public long between(java.time.temporal.Temporal, java.time.temporal.Temporal);
+    method public java.time.Duration getDuration();
+    method public boolean isDateBased();
+    method public boolean isDurationEstimated();
+    method public boolean isSupportedBy(java.time.temporal.Temporal);
+    method public boolean isTimeBased();
+    method public static java.time.temporal.ChronoUnit valueOf(java.lang.String);
+    method public static final java.time.temporal.ChronoUnit[] values();
+    enum_constant public static final java.time.temporal.ChronoUnit CENTURIES;
+    enum_constant public static final java.time.temporal.ChronoUnit DAYS;
+    enum_constant public static final java.time.temporal.ChronoUnit DECADES;
+    enum_constant public static final java.time.temporal.ChronoUnit ERAS;
+    enum_constant public static final java.time.temporal.ChronoUnit FOREVER;
+    enum_constant public static final java.time.temporal.ChronoUnit HALF_DAYS;
+    enum_constant public static final java.time.temporal.ChronoUnit HOURS;
+    enum_constant public static final java.time.temporal.ChronoUnit MICROS;
+    enum_constant public static final java.time.temporal.ChronoUnit MILLENNIA;
+    enum_constant public static final java.time.temporal.ChronoUnit MILLIS;
+    enum_constant public static final java.time.temporal.ChronoUnit MINUTES;
+    enum_constant public static final java.time.temporal.ChronoUnit MONTHS;
+    enum_constant public static final java.time.temporal.ChronoUnit NANOS;
+    enum_constant public static final java.time.temporal.ChronoUnit SECONDS;
+    enum_constant public static final java.time.temporal.ChronoUnit WEEKS;
+    enum_constant public static final java.time.temporal.ChronoUnit YEARS;
+  }
+
+  public final class IsoFields {
+    field public static final java.time.temporal.TemporalField DAY_OF_QUARTER;
+    field public static final java.time.temporal.TemporalField QUARTER_OF_YEAR;
+    field public static final java.time.temporal.TemporalUnit QUARTER_YEARS;
+    field public static final java.time.temporal.TemporalField WEEK_BASED_YEAR;
+    field public static final java.time.temporal.TemporalUnit WEEK_BASED_YEARS;
+    field public static final java.time.temporal.TemporalField WEEK_OF_WEEK_BASED_YEAR;
+  }
+
+  public final class JulianFields {
+    field public static final java.time.temporal.TemporalField JULIAN_DAY;
+    field public static final java.time.temporal.TemporalField MODIFIED_JULIAN_DAY;
+    field public static final java.time.temporal.TemporalField RATA_DIE;
+  }
+
+  public abstract interface Temporal implements java.time.temporal.TemporalAccessor {
+    method public abstract boolean isSupported(java.time.temporal.TemporalUnit);
+    method public default java.time.temporal.Temporal minus(java.time.temporal.TemporalAmount);
+    method public default java.time.temporal.Temporal minus(long, java.time.temporal.TemporalUnit);
+    method public default java.time.temporal.Temporal plus(java.time.temporal.TemporalAmount);
+    method public abstract java.time.temporal.Temporal plus(long, java.time.temporal.TemporalUnit);
+    method public abstract long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public default java.time.temporal.Temporal with(java.time.temporal.TemporalAdjuster);
+    method public abstract java.time.temporal.Temporal with(java.time.temporal.TemporalField, long);
+  }
+
+  public abstract interface TemporalAccessor {
+    method public default int get(java.time.temporal.TemporalField);
+    method public abstract long getLong(java.time.temporal.TemporalField);
+    method public abstract boolean isSupported(java.time.temporal.TemporalField);
+    method public default <R> R query(java.time.temporal.TemporalQuery<R>);
+    method public default java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
+  }
+
+  public abstract interface TemporalAdjuster {
+    method public abstract java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+  }
+
+  public final class TemporalAdjusters {
+    method public static java.time.temporal.TemporalAdjuster dayOfWeekInMonth(int, java.time.DayOfWeek);
+    method public static java.time.temporal.TemporalAdjuster firstDayOfMonth();
+    method public static java.time.temporal.TemporalAdjuster firstDayOfNextMonth();
+    method public static java.time.temporal.TemporalAdjuster firstDayOfNextYear();
+    method public static java.time.temporal.TemporalAdjuster firstDayOfYear();
+    method public static java.time.temporal.TemporalAdjuster firstInMonth(java.time.DayOfWeek);
+    method public static java.time.temporal.TemporalAdjuster lastDayOfMonth();
+    method public static java.time.temporal.TemporalAdjuster lastDayOfYear();
+    method public static java.time.temporal.TemporalAdjuster lastInMonth(java.time.DayOfWeek);
+    method public static java.time.temporal.TemporalAdjuster next(java.time.DayOfWeek);
+    method public static java.time.temporal.TemporalAdjuster nextOrSame(java.time.DayOfWeek);
+    method public static java.time.temporal.TemporalAdjuster ofDateAdjuster(java.util.function.UnaryOperator<java.time.LocalDate>);
+    method public static java.time.temporal.TemporalAdjuster previous(java.time.DayOfWeek);
+    method public static java.time.temporal.TemporalAdjuster previousOrSame(java.time.DayOfWeek);
+  }
+
+  public abstract interface TemporalAmount {
+    method public abstract java.time.temporal.Temporal addTo(java.time.temporal.Temporal);
+    method public abstract long get(java.time.temporal.TemporalUnit);
+    method public abstract java.util.List<java.time.temporal.TemporalUnit> getUnits();
+    method public abstract java.time.temporal.Temporal subtractFrom(java.time.temporal.Temporal);
+  }
+
+  public abstract interface TemporalField {
+    method public abstract <R extends java.time.temporal.Temporal> R adjustInto(R, long);
+    method public abstract java.time.temporal.TemporalUnit getBaseUnit();
+    method public default java.lang.String getDisplayName(java.util.Locale);
+    method public abstract long getFrom(java.time.temporal.TemporalAccessor);
+    method public abstract java.time.temporal.TemporalUnit getRangeUnit();
+    method public abstract boolean isDateBased();
+    method public abstract boolean isSupportedBy(java.time.temporal.TemporalAccessor);
+    method public abstract boolean isTimeBased();
+    method public abstract java.time.temporal.ValueRange range();
+    method public abstract java.time.temporal.ValueRange rangeRefinedBy(java.time.temporal.TemporalAccessor);
+    method public default java.time.temporal.TemporalAccessor resolve(java.util.Map<java.time.temporal.TemporalField, java.lang.Long>, java.time.temporal.TemporalAccessor, java.time.format.ResolverStyle);
+    method public abstract java.lang.String toString();
+  }
+
+  public final class TemporalQueries {
+    method public static java.time.temporal.TemporalQuery<java.time.chrono.Chronology> chronology();
+    method public static java.time.temporal.TemporalQuery<java.time.LocalDate> localDate();
+    method public static java.time.temporal.TemporalQuery<java.time.LocalTime> localTime();
+    method public static java.time.temporal.TemporalQuery<java.time.ZoneOffset> offset();
+    method public static java.time.temporal.TemporalQuery<java.time.temporal.TemporalUnit> precision();
+    method public static java.time.temporal.TemporalQuery<java.time.ZoneId> zone();
+    method public static java.time.temporal.TemporalQuery<java.time.ZoneId> zoneId();
+  }
+
+  public abstract interface TemporalQuery<R> {
+    method public abstract R queryFrom(java.time.temporal.TemporalAccessor);
+  }
+
+  public abstract interface TemporalUnit {
+    method public abstract <R extends java.time.temporal.Temporal> R addTo(R, long);
+    method public abstract long between(java.time.temporal.Temporal, java.time.temporal.Temporal);
+    method public abstract java.time.Duration getDuration();
+    method public abstract boolean isDateBased();
+    method public abstract boolean isDurationEstimated();
+    method public default boolean isSupportedBy(java.time.temporal.Temporal);
+    method public abstract boolean isTimeBased();
+    method public abstract java.lang.String toString();
+  }
+
+  public class UnsupportedTemporalTypeException extends java.time.DateTimeException {
+    ctor public UnsupportedTemporalTypeException(java.lang.String);
+    ctor public UnsupportedTemporalTypeException(java.lang.String, java.lang.Throwable);
+  }
+
+  public final class ValueRange implements java.io.Serializable {
+    method public int checkValidIntValue(long, java.time.temporal.TemporalField);
+    method public long checkValidValue(long, java.time.temporal.TemporalField);
+    method public long getLargestMinimum();
+    method public long getMaximum();
+    method public long getMinimum();
+    method public long getSmallestMaximum();
+    method public boolean isFixed();
+    method public boolean isIntValue();
+    method public boolean isValidIntValue(long);
+    method public boolean isValidValue(long);
+    method public static java.time.temporal.ValueRange of(long, long);
+    method public static java.time.temporal.ValueRange of(long, long, long);
+    method public static java.time.temporal.ValueRange of(long, long, long, long);
+  }
+
+  public final class WeekFields implements java.io.Serializable {
+    method public java.time.temporal.TemporalField dayOfWeek();
+    method public java.time.DayOfWeek getFirstDayOfWeek();
+    method public int getMinimalDaysInFirstWeek();
+    method public static java.time.temporal.WeekFields of(java.util.Locale);
+    method public static java.time.temporal.WeekFields of(java.time.DayOfWeek, int);
+    method public java.time.temporal.TemporalField weekBasedYear();
+    method public java.time.temporal.TemporalField weekOfMonth();
+    method public java.time.temporal.TemporalField weekOfWeekBasedYear();
+    method public java.time.temporal.TemporalField weekOfYear();
+    field public static final java.time.temporal.WeekFields ISO;
+    field public static final java.time.temporal.WeekFields SUNDAY_START;
+    field public static final java.time.temporal.TemporalUnit WEEK_BASED_YEARS;
+  }
+
+}
+
+package java.time.zone {
+
+  public final class ZoneOffsetTransition implements java.lang.Comparable java.io.Serializable {
+    method public int compareTo(java.time.zone.ZoneOffsetTransition);
+    method public java.time.LocalDateTime getDateTimeAfter();
+    method public java.time.LocalDateTime getDateTimeBefore();
+    method public java.time.Duration getDuration();
+    method public java.time.Instant getInstant();
+    method public java.time.ZoneOffset getOffsetAfter();
+    method public java.time.ZoneOffset getOffsetBefore();
+    method public boolean isGap();
+    method public boolean isOverlap();
+    method public boolean isValidOffset(java.time.ZoneOffset);
+    method public static java.time.zone.ZoneOffsetTransition of(java.time.LocalDateTime, java.time.ZoneOffset, java.time.ZoneOffset);
+    method public long toEpochSecond();
+  }
+
+  public final class ZoneOffsetTransitionRule implements java.io.Serializable {
+    method public java.time.zone.ZoneOffsetTransition createTransition(int);
+    method public int getDayOfMonthIndicator();
+    method public java.time.DayOfWeek getDayOfWeek();
+    method public java.time.LocalTime getLocalTime();
+    method public java.time.Month getMonth();
+    method public java.time.ZoneOffset getOffsetAfter();
+    method public java.time.ZoneOffset getOffsetBefore();
+    method public java.time.ZoneOffset getStandardOffset();
+    method public java.time.zone.ZoneOffsetTransitionRule.TimeDefinition getTimeDefinition();
+    method public boolean isMidnightEndOfDay();
+    method public static java.time.zone.ZoneOffsetTransitionRule of(java.time.Month, int, java.time.DayOfWeek, java.time.LocalTime, boolean, java.time.zone.ZoneOffsetTransitionRule.TimeDefinition, java.time.ZoneOffset, java.time.ZoneOffset, java.time.ZoneOffset);
+  }
+
+  public static final class ZoneOffsetTransitionRule.TimeDefinition extends java.lang.Enum {
+    method public java.time.LocalDateTime createDateTime(java.time.LocalDateTime, java.time.ZoneOffset, java.time.ZoneOffset);
+    method public static java.time.zone.ZoneOffsetTransitionRule.TimeDefinition valueOf(java.lang.String);
+    method public static final java.time.zone.ZoneOffsetTransitionRule.TimeDefinition[] values();
+    enum_constant public static final java.time.zone.ZoneOffsetTransitionRule.TimeDefinition STANDARD;
+    enum_constant public static final java.time.zone.ZoneOffsetTransitionRule.TimeDefinition UTC;
+    enum_constant public static final java.time.zone.ZoneOffsetTransitionRule.TimeDefinition WALL;
+  }
+
+  public final class ZoneRules implements java.io.Serializable {
+    method public java.time.Duration getDaylightSavings(java.time.Instant);
+    method public java.time.ZoneOffset getOffset(java.time.Instant);
+    method public java.time.ZoneOffset getOffset(java.time.LocalDateTime);
+    method public java.time.ZoneOffset getStandardOffset(java.time.Instant);
+    method public java.time.zone.ZoneOffsetTransition getTransition(java.time.LocalDateTime);
+    method public java.util.List<java.time.zone.ZoneOffsetTransitionRule> getTransitionRules();
+    method public java.util.List<java.time.zone.ZoneOffsetTransition> getTransitions();
+    method public java.util.List<java.time.ZoneOffset> getValidOffsets(java.time.LocalDateTime);
+    method public boolean isDaylightSavings(java.time.Instant);
+    method public boolean isFixedOffset();
+    method public boolean isValidOffset(java.time.LocalDateTime, java.time.ZoneOffset);
+    method public java.time.zone.ZoneOffsetTransition nextTransition(java.time.Instant);
+    method public static java.time.zone.ZoneRules of(java.time.ZoneOffset, java.time.ZoneOffset, java.util.List<java.time.zone.ZoneOffsetTransition>, java.util.List<java.time.zone.ZoneOffsetTransition>, java.util.List<java.time.zone.ZoneOffsetTransitionRule>);
+    method public static java.time.zone.ZoneRules of(java.time.ZoneOffset);
+    method public java.time.zone.ZoneOffsetTransition previousTransition(java.time.Instant);
+  }
+
+  public class ZoneRulesException extends java.time.DateTimeException {
+    ctor public ZoneRulesException(java.lang.String);
+    ctor public ZoneRulesException(java.lang.String, java.lang.Throwable);
+  }
+
+}
+
 package java.util {
 
   public abstract class AbstractCollection<E> implements java.util.Collection {
@@ -58795,7 +60425,9 @@
     method public int get(int);
     method public int getActualMaximum(int);
     method public int getActualMinimum(int);
+    method public static java.util.Set<java.lang.String> getAvailableCalendarTypes();
     method public static synchronized java.util.Locale[] getAvailableLocales();
+    method public java.lang.String getCalendarType();
     method public java.lang.String getDisplayName(int, int, java.util.Locale);
     method public java.util.Map<java.lang.String, java.lang.Integer> getDisplayNames(int, int, java.util.Locale);
     method public int getFirstDayOfWeek();
@@ -58830,6 +60462,7 @@
     method public void setTimeInMillis(long);
     method public void setTimeZone(java.util.TimeZone);
     method public void setWeekDate(int, int, int);
+    method public final java.time.Instant toInstant();
     field public static final int ALL_STYLES = 0; // 0x0
     field public static final int AM = 0; // 0x0
     field public static final int AM_PM = 9; // 0x9
@@ -58852,12 +60485,16 @@
     field public static final int JULY = 6; // 0x6
     field public static final int JUNE = 5; // 0x5
     field public static final int LONG = 2; // 0x2
+    field public static final int LONG_FORMAT = 2; // 0x2
+    field public static final int LONG_STANDALONE = 32770; // 0x8002
     field public static final int MARCH = 2; // 0x2
     field public static final int MAY = 4; // 0x4
     field public static final int MILLISECOND = 14; // 0xe
     field public static final int MINUTE = 12; // 0xc
     field public static final int MONDAY = 2; // 0x2
     field public static final int MONTH = 2; // 0x2
+    field public static final int NARROW_FORMAT = 4; // 0x4
+    field public static final int NARROW_STANDALONE = 32772; // 0x8004
     field public static final int NOVEMBER = 10; // 0xa
     field public static final int OCTOBER = 9; // 0x9
     field public static final int PM = 1; // 0x1
@@ -58865,6 +60502,8 @@
     field public static final int SECOND = 13; // 0xd
     field public static final int SEPTEMBER = 8; // 0x8
     field public static final int SHORT = 1; // 0x1
+    field public static final int SHORT_FORMAT = 1; // 0x1
+    field public static final int SHORT_STANDALONE = 32769; // 0x8001
     field public static final int SUNDAY = 1; // 0x1
     field public static final int THURSDAY = 5; // 0x5
     field public static final int TUESDAY = 3; // 0x3
@@ -58881,6 +60520,24 @@
     field protected long time;
   }
 
+  public static class Calendar.Builder {
+    ctor public Calendar.Builder();
+    method public java.util.Calendar build();
+    method public java.util.Calendar.Builder set(int, int);
+    method public java.util.Calendar.Builder setCalendarType(java.lang.String);
+    method public java.util.Calendar.Builder setDate(int, int, int);
+    method public java.util.Calendar.Builder setFields(int...);
+    method public java.util.Calendar.Builder setInstant(long);
+    method public java.util.Calendar.Builder setInstant(java.util.Date);
+    method public java.util.Calendar.Builder setLenient(boolean);
+    method public java.util.Calendar.Builder setLocale(java.util.Locale);
+    method public java.util.Calendar.Builder setTimeOfDay(int, int, int);
+    method public java.util.Calendar.Builder setTimeOfDay(int, int, int, int);
+    method public java.util.Calendar.Builder setTimeZone(java.util.TimeZone);
+    method public java.util.Calendar.Builder setWeekDate(int, int, int);
+    method public java.util.Calendar.Builder setWeekDefinition(int, int);
+  }
+
   public abstract interface Collection<E> implements java.lang.Iterable {
     method public abstract boolean add(E);
     method public abstract boolean addAll(java.util.Collection<? extends E>);
@@ -59016,6 +60673,7 @@
     method public boolean before(java.util.Date);
     method public java.lang.Object clone();
     method public int compareTo(java.util.Date);
+    method public static java.util.Date from(java.time.Instant);
     method public deprecated int getDate();
     method public deprecated int getDay();
     method public deprecated int getHours();
@@ -59034,6 +60692,7 @@
     method public void setTime(long);
     method public deprecated void setYear(int);
     method public deprecated java.lang.String toGMTString();
+    method public java.time.Instant toInstant();
     method public deprecated java.lang.String toLocaleString();
   }
 
@@ -59203,6 +60862,7 @@
     method public void add(int, int);
     method protected void computeFields();
     method protected void computeTime();
+    method public static java.util.GregorianCalendar from(java.time.ZonedDateTime);
     method public int getGreatestMinimum(int);
     method public final java.util.Date getGregorianChange();
     method public int getLeastMaximum(int);
@@ -59212,6 +60872,7 @@
     method public final boolean isWeekDateSupported();
     method public void roll(int, boolean);
     method public void setGregorianChange(java.util.Date);
+    method public java.time.ZonedDateTime toZonedDateTime();
     field public static final int AD = 1; // 0x1
     field public static final int BC = 0; // 0x0
   }
@@ -60239,12 +61900,14 @@
     method public int getOffset(long);
     method public abstract int getRawOffset();
     method public static synchronized java.util.TimeZone getTimeZone(java.lang.String);
+    method public static java.util.TimeZone getTimeZone(java.time.ZoneId);
     method public boolean hasSameRules(java.util.TimeZone);
     method public abstract boolean inDaylightTime(java.util.Date);
     method public boolean observesDaylightTime();
     method public static synchronized void setDefault(java.util.TimeZone);
     method public void setID(java.lang.String);
     method public abstract void setRawOffset(int);
+    method public java.time.ZoneId toZoneId();
     method public abstract boolean useDaylightTime();
     field public static final int LONG = 1; // 0x1
     field public static final int SHORT = 0; // 0x0
@@ -60851,31 +62514,31 @@
     ctor public CopyOnWriteArrayList();
     ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
     ctor public CopyOnWriteArrayList(E[]);
-    method public synchronized boolean add(E);
-    method public synchronized void add(int, E);
-    method public synchronized boolean addAll(java.util.Collection<? extends E>);
-    method public synchronized boolean addAll(int, java.util.Collection<? extends E>);
-    method public synchronized int addAllAbsent(java.util.Collection<? extends E>);
-    method public synchronized boolean addIfAbsent(E);
-    method public synchronized void clear();
+    method public boolean add(E);
+    method public void add(int, E);
+    method public boolean addAll(java.util.Collection<? extends E>);
+    method public boolean addAll(int, java.util.Collection<? extends E>);
+    method public int addAllAbsent(java.util.Collection<? extends E>);
+    method public boolean addIfAbsent(E);
+    method public void clear();
     method public java.lang.Object clone();
     method public boolean contains(java.lang.Object);
     method public boolean containsAll(java.util.Collection<?>);
     method public void forEach(java.util.function.Consumer<? super E>);
     method public E get(int);
-    method public int indexOf(E, int);
     method public int indexOf(java.lang.Object);
+    method public int indexOf(E, int);
     method public boolean isEmpty();
     method public java.util.Iterator<E> iterator();
-    method public int lastIndexOf(E, int);
     method public int lastIndexOf(java.lang.Object);
-    method public java.util.ListIterator<E> listIterator(int);
+    method public int lastIndexOf(E, int);
     method public java.util.ListIterator<E> listIterator();
-    method public synchronized E remove(int);
-    method public synchronized boolean remove(java.lang.Object);
-    method public synchronized boolean removeAll(java.util.Collection<?>);
-    method public synchronized boolean retainAll(java.util.Collection<?>);
-    method public synchronized E set(int, E);
+    method public java.util.ListIterator<E> listIterator(int);
+    method public E remove(int);
+    method public boolean remove(java.lang.Object);
+    method public boolean removeAll(java.util.Collection<?>);
+    method public boolean retainAll(java.util.Collection<?>);
+    method public E set(int, E);
     method public int size();
     method public java.util.List<E> subList(int, int);
     method public java.lang.Object[] toArray();
@@ -62726,10 +64389,12 @@
     method public java.lang.StringBuffer appendTail(java.lang.StringBuffer);
     method public int end();
     method public int end(int);
+    method public int end(java.lang.String);
     method public boolean find();
     method public boolean find(int);
     method public java.lang.String group();
     method public java.lang.String group(int);
+    method public java.lang.String group(java.lang.String);
     method public int groupCount();
     method public boolean hasAnchoringBounds();
     method public boolean hasTransparentBounds();
@@ -62748,6 +64413,7 @@
     method public java.util.regex.Matcher reset(java.lang.CharSequence);
     method public int start();
     method public int start(int) throws java.lang.IllegalStateException;
+    method public int start(java.lang.String);
     method public java.util.regex.MatchResult toMatchResult();
     method public java.util.regex.Matcher useAnchoringBounds(boolean);
     method public java.util.regex.Matcher usePattern(java.util.regex.Pattern);
diff --git a/compiled-classes-phone b/compiled-classes-phone
index 221d687..ec3371e 100644
--- a/compiled-classes-phone
+++ b/compiled-classes-phone
@@ -632,6 +632,7 @@
 android.bluetooth.BluetoothAudioConfig
 android.bluetooth.BluetoothClass
 android.bluetooth.BluetoothClass$1
+android.bluetooth.BluetoothCodecConfig
 android.bluetooth.BluetoothDevice
 android.bluetooth.BluetoothDevice$1
 android.bluetooth.BluetoothDevice$2
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 8f42467..857a361 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -509,10 +509,23 @@
      * Common-path handling of app data dir creation
      */
     private static File ensurePrivateDirExists(File file) {
+        return ensurePrivateDirExists(file, 0771, -1);
+    }
+
+    private static File ensurePrivateCacheDirExists(File file) {
+        final int gid = UserHandle.getCacheAppGid(Process.myUid());
+        return ensurePrivateDirExists(file, 02771, gid);
+    }
+
+    private static File ensurePrivateDirExists(File file, int mode, int gid) {
         if (!file.exists()) {
+            final String path = file.getAbsolutePath();
             try {
-                Os.mkdir(file.getAbsolutePath(), 0771);
-                Os.chmod(file.getAbsolutePath(), 0771);
+                Os.mkdir(path, mode);
+                Os.chmod(path, mode);
+                if (gid != -1) {
+                    Os.chown(path, -1, gid);
+                }
             } catch (ErrnoException e) {
                 if (e.errno == OsConstants.EEXIST) {
                     // We must have raced with someone; that's okay
@@ -581,7 +594,7 @@
             if (mCacheDir == null) {
                 mCacheDir = new File(getDataDir(), "cache");
             }
-            return ensurePrivateDirExists(mCacheDir);
+            return ensurePrivateCacheDirExists(mCacheDir);
         }
     }
 
@@ -591,7 +604,7 @@
             if (mCodeCacheDir == null) {
                 mCodeCacheDir = new File(getDataDir(), "code_cache");
             }
-            return ensurePrivateDirExists(mCodeCacheDir);
+            return ensurePrivateCacheDirExists(mCodeCacheDir);
         }
     }
 
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 353c640..1165fce 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -102,6 +102,27 @@
         "android.bluetooth.a2dp.profile.action.AVRCP_CONNECTION_STATE_CHANGED";
 
     /**
+     * Intent used to broadcast the change in the Audio Codec state of the
+     * A2DP Source profile.
+     *
+     * <p>This intent will have 3 extras:
+     * <ul>
+     *   <li> {@link #EXTRA_CODEC_CONFIG} - The current codec configuration. </li>
+     *   <li> {@link #EXTRA_PREVIOUS_CODEC_CONFIG} - The previous codec configuration. </li>
+     *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device if the device is currently
+     *   connected, otherwise it is not included.</li>
+     * </ul>
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+     * receive.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_CODEC_CONFIG_CHANGED =
+        "android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED";
+
+    /**
      * A2DP sink device is streaming music. This state can be one of
      * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
      * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
@@ -543,6 +564,54 @@
     }
 
     /**
+     * Gets the current codec configuration.
+     *
+     * @return the current codec configuration
+     * @hide
+     */
+    public BluetoothCodecConfig getCodecConfig() {
+        if (DBG) Log.d(TAG, "getCodecConfig");
+        try {
+            mServiceLock.readLock().lock();
+            if (mService != null && isEnabled()) {
+                return mService.getCodecConfig();
+            }
+            if (mService == null) {
+                Log.w(TAG, "Proxy not attached to service");
+            }
+            return null;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error talking to BT service in getCodecConfig()", e);
+            return null;
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+    }
+
+    /**
+     * Sets the codec configuration preference.
+     *
+     * @param codecConfig the codec configuration preference
+     * @hide
+     */
+    public void setCodecConfigPreference(BluetoothCodecConfig codecConfig) {
+        if (DBG) Log.d(TAG, "setCodecConfigPreference");
+        try {
+            mServiceLock.readLock().lock();
+            if (mService != null && isEnabled()) {
+                mService.setCodecConfigPreference(codecConfig);
+            }
+            if (mService == null) Log.w(TAG, "Proxy not attached to service");
+            return;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error talking to BT service in setCodecConfigPreference()", e);
+            return;
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+    }
+
+    /**
      * Helper for converting a state to a string.
      *
      * For debug use only - strings are not internationalized.
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl b/core/java/android/bluetooth/BluetoothCodecConfig.aidl
similarity index 89%
copy from wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
copy to core/java/android/bluetooth/BluetoothCodecConfig.aidl
index a35e71d..553e66e 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
+++ b/core/java/android/bluetooth/BluetoothCodecConfig.aidl
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.net.wifi.aware;
+package android.bluetooth;
 
-parcelable WifiAwareCharacteristics;
+parcelable BluetoothCodecConfig;
diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java
new file mode 100644
index 0000000..52cd2de
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothCodecConfig.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Represents the codec configuration for a Bluetooth A2DP source device.
+ *
+ * {@see BluetoothA2dp}
+ *
+ * {@hide}
+ */
+public final class BluetoothCodecConfig implements Parcelable {
+
+    /**
+     * Extra for the codec configuration intents of the individual profiles.
+     *
+     * This extra represents the current codec configuration of the A2DP
+     * profile.
+     */
+    public static final String EXTRA_CODEC_CONFIG = "android.bluetooth.codec.extra.CODEC_CONFIG";
+
+    /**
+     * Extra for the codec configuration intents of the individual profiles.
+     *
+     * This extra represents the previous codec configuration of the A2DP
+     * profile.
+     */
+    public static final String EXTRA_PREVIOUS_CODEC_CONFIG =
+        "android.bluetooth.codec.extra.PREVIOUS_CODEC_CONFIG";
+
+    // Add an entry for each source codec here.
+    // NOTE: The values should be same as those listed in the following file:
+    //   hardware/libhardware/include/hardware/bt_av.h
+    public static final int SOURCE_CODEC_TYPE_SBC     = 0;
+    public static final int SOURCE_CODEC_TYPE_APTX    = 1;
+    public static final int SOURCE_CODEC_TYPE_APTX_HD = 2;
+    public static final int SOURCE_CODEC_TYPE_LDAC    = 3;
+
+    public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000;
+
+    public static final int CODEC_PRIORITY_DEFAULT = 0;
+    public static final int CODEC_PRIORITY_HIGHEST = 1000 * 1000;
+
+    public static final int SAMPLE_RATE_NONE   = 0;
+    public static final int SAMPLE_RATE_44100  = 0x1 << 0;
+    public static final int SAMPLE_RATE_48000  = 0x1 << 1;
+    public static final int SAMPLE_RATE_88200  = 0x1 << 2;
+    public static final int SAMPLE_RATE_96000  = 0x1 << 3;
+    public static final int SAMPLE_RATE_176400 = 0x1 << 4;
+    public static final int SAMPLE_RATE_192000 = 0x1 << 5;
+
+    public static final int BITS_PER_SAMPLE_NONE = 0;
+    public static final int BITS_PER_SAMPLE_16   = 0x1 << 0;
+    public static final int BITS_PER_SAMPLE_24   = 0x1 << 1;
+    public static final int BITS_PER_SAMPLE_32   = 0x1 << 2;
+
+    public static final int CHANNEL_MODE_NONE   = 0;
+    public static final int CHANNEL_MODE_MONO   = 0x1 << 0;
+    public static final int CHANNEL_MODE_STEREO = 0x1 << 1;
+
+    private final int mCodecType;
+    private final int mCodecPriority;
+    private final int mSampleRate;
+    private final int mBitsPerSample;
+    private final int mChannelMode;
+    private final long mCodecSpecific1;
+    private final long mCodecSpecific2;
+    private final long mCodecSpecific3;
+    private final long mCodecSpecific4;
+
+    public BluetoothCodecConfig(int codecType, int codecPriority,
+                                int sampleRate, int bitsPerSample,
+                                int channelMode,long codecSpecific1,
+                                long codecSpecific2, long codecSpecific3,
+                                long codecSpecific4) {
+        mCodecType = codecType;
+        mCodecPriority = codecPriority;
+        mSampleRate = sampleRate;
+        mBitsPerSample = bitsPerSample;
+        mChannelMode = channelMode;
+        mCodecSpecific1 = codecSpecific1;
+        mCodecSpecific2 = codecSpecific2;
+        mCodecSpecific3 = codecSpecific3;
+        mCodecSpecific4 = codecSpecific4;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof BluetoothCodecConfig) {
+            BluetoothCodecConfig other = (BluetoothCodecConfig)o;
+            return (other.mCodecType == mCodecType &&
+                    other.mCodecPriority == mCodecPriority &&
+                    other.mSampleRate == mSampleRate &&
+                    other.mBitsPerSample == mBitsPerSample &&
+                    other.mChannelMode == mChannelMode &&
+                    other.mCodecSpecific1 == mCodecSpecific1 &&
+                    other.mCodecSpecific2 == mCodecSpecific2 &&
+                    other.mCodecSpecific3 == mCodecSpecific3 &&
+                    other.mCodecSpecific4 == mCodecSpecific4);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mCodecType, mCodecPriority, mSampleRate,
+                            mBitsPerSample, mChannelMode, mCodecSpecific1,
+                            mCodecSpecific2, mCodecSpecific3, mCodecSpecific4);
+    }
+
+    @Override
+    public String toString() {
+        return "{mCodecType:" + mCodecType +
+            ",mCodecPriority:" + mCodecPriority +
+            ",mSampleRate:" + String.format("0x%x", mSampleRate) +
+            ",mBitsPerSample:" + String.format("0x%x", mBitsPerSample) +
+            ",mChannelMode:" + String.format("0x%x", mChannelMode) +
+            ",mCodecSpecific1:" + mCodecSpecific1 +
+            ",mCodecSpecific2:" + mCodecSpecific2 +
+            ",mCodecSpecific3:" + mCodecSpecific3 +
+            ",mCodecSpecific4:" + mCodecSpecific4 + "}";
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<BluetoothCodecConfig> CREATOR =
+            new Parcelable.Creator<BluetoothCodecConfig>() {
+        public BluetoothCodecConfig createFromParcel(Parcel in) {
+            final int codecType = in.readInt();
+            final int codecPriority = in.readInt();
+            final int sampleRate = in.readInt();
+            final int bitsPerSample = in.readInt();
+            final int channelMode = in.readInt();
+            final long codecSpecific1 = in.readLong();
+            final long codecSpecific2 = in.readLong();
+            final long codecSpecific3 = in.readLong();
+            final long codecSpecific4 = in.readLong();
+            return new BluetoothCodecConfig(codecType, codecPriority,
+                                            sampleRate, bitsPerSample,
+                                            channelMode, codecSpecific1,
+                                            codecSpecific2, codecSpecific3,
+                                            codecSpecific4);
+        }
+        public BluetoothCodecConfig[] newArray(int size) {
+            return new BluetoothCodecConfig[size];
+        }
+    };
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mCodecType);
+        out.writeInt(mCodecPriority);
+        out.writeInt(mSampleRate);
+        out.writeInt(mBitsPerSample);
+        out.writeInt(mChannelMode);
+        out.writeLong(mCodecSpecific1);
+        out.writeLong(mCodecSpecific2);
+        out.writeLong(mCodecSpecific3);
+        out.writeLong(mCodecSpecific4);
+    }
+
+    /**
+     * Returns the codec type.
+     * See {@link android.bluetooth.BluetoothCodecConfig#SOURCE_CODEC_TYPE_SBC}.
+     *
+     * @return the codec type
+     */
+    public int getCodecType() {
+        return mCodecType;
+    }
+
+    /**
+     * Returns the codec selection priority.
+     * The codec selection priority is relative to other codecs: larger value
+     * means higher priority. If 0, reset to default.
+     *
+     * @return the codec priority
+     */
+    public int getCodecPriority() {
+        return mCodecPriority;
+    }
+
+    /**
+     * Returns the codec sample rate. The value can be a bitmask with all
+     * supported sample rates:
+     * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_NONE} or
+     * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_44100} or
+     * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_48000} or
+     * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_88200} or
+     * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_96000} or
+     * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_176400} or
+     * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_192000}
+     *
+     * @return the codec sample rate
+     */
+    public int getSampleRate() {
+        return mSampleRate;
+    }
+
+    /**
+     * Returns the codec bits per sample. The value can be a bitmask with all
+     * bits per sample supported:
+     * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_NONE} or
+     * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_16} or
+     * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_24} or
+     * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_32}
+     *
+     * @return the codec bits per sample
+     */
+    public int getBitsPerSample() {
+        return mBitsPerSample;
+    }
+
+    /**
+     * Returns the codec channel mode. The value can be a bitmask with all
+     * supported channel modes:
+     * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_NONE} or
+     * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_MONO} or
+     * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_STEREO}
+     *
+     * @return the codec channel mode
+     */
+    public int getChannelMode() {
+        return mChannelMode;
+    }
+
+    /**
+     * Returns a codec specific value1.
+     *
+     * @return a codec specific value1.
+     */
+    public long getCodecSpecific1() {
+        return mCodecSpecific1;
+    }
+
+    /**
+     * Returns a codec specific value2.
+     *
+     * @return a codec specific value2
+     */
+    public long getCodecSpecific2() {
+        return mCodecSpecific2;
+    }
+
+    /**
+     * Returns a codec specific value3.
+     *
+     * @return a codec specific value3
+     */
+    public long getCodecSpecific3() {
+        return mCodecSpecific3;
+    }
+
+    /**
+     * Returns a codec specific value4.
+     *
+     * @return a codec specific value4
+     */
+    public long getCodecSpecific4() {
+        return mCodecSpecific4;
+    }
+
+    /**
+     * Checks whether the audio feeding parameters are same.
+     *
+     * @param other the codec config to compare against
+     * @return true if the audio feeding parameters are same, otherwise false
+     */
+    public boolean sameAudioFeedingParameters(BluetoothCodecConfig other) {
+        return (other != null && other.mSampleRate == mSampleRate &&
+                other.mBitsPerSample == mBitsPerSample &&
+                other.mChannelMode == mChannelMode);
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
index 0f0e050..f519776 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
@@ -45,9 +45,9 @@
      *            <code>false</code> otherwise.
      */
     public void onAppStatusChanged(BluetoothDevice pluggedDevice,
-                                    BluetoothHidDeviceAppConfiguration config, boolean registered) {
-        Log.d(TAG, "onAppStatusChanged: pluggedDevice=" + (pluggedDevice == null ?
-            null : pluggedDevice.toString()) + " registered=" + registered);
+            BluetoothHidDeviceAppConfiguration config, boolean registered) {
+        Log.d(TAG, "onAppStatusChanged: pluggedDevice=" + pluggedDevice + " registered="
+                + registered);
     }
 
     /**
@@ -60,13 +60,13 @@
      * @param state Connection state as defined in {@link BluetoothProfile}.
      */
     public void onConnectionStateChanged(BluetoothDevice device, int state) {
-        Log.d(TAG, "onConnectionStateChanged: device=" + device.toString() + " state=" + state);
+        Log.d(TAG, "onConnectionStateChanged: device=" + device + " state=" + state);
     }
 
     /**
      * Callback called when GET_REPORT is received from remote host. Should be
      * replied by application using
-     * {@link BluetoothHidDevice#replyReport(byte, byte, byte[])}.
+     * {@link BluetoothHidDevice#replyReport(BluetoothDevice, byte, byte, byte[])}.
      *
      * @param type Requested Report Type.
      * @param id Requested Report Id, can be 0 if no Report Id are defined in
@@ -74,21 +74,22 @@
      * @param bufferSize Requested buffer size, application shall respond with
      *            at least given number of bytes.
      */
-    public void onGetReport(byte type, byte id, int bufferSize) {
-        Log.d(TAG, "onGetReport: type=" + type + " id=" + id + " bufferSize=" + bufferSize);
+    public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) {
+        Log.d(TAG, "onGetReport: device=" + device + " type=" + type + " id=" + id + " bufferSize="
+                + bufferSize);
     }
 
     /**
      * Callback called when SET_REPORT is received from remote host. In case
      * received data are invalid, application shall respond with
-     * {@link BluetoothHidDevice#reportError()}.
+     * {@link BluetoothHidDevice#reportError(BluetoothDevice)}.
      *
      * @param type Report Type.
      * @param id Report Id.
      * @param data Report data.
      */
-    public void onSetReport(byte type, byte id, byte[] data) {
-        Log.d(TAG, "onSetReport: type=" + type + " id=" + id);
+    public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) {
+        Log.d(TAG, "onSetReport: device=" + device + " type=" + type + " id=" + id);
     }
 
     /**
@@ -99,8 +100,8 @@
      *
      * @param protocol Protocol Mode.
      */
-    public void onSetProtocol(byte protocol) {
-        Log.d(TAG, "onSetProtocol: protocol=" + protocol);
+    public void onSetProtocol(BluetoothDevice device, byte protocol) {
+        Log.d(TAG, "onSetProtocol: device=" + device + " protocol=" + protocol);
     }
 
     /**
@@ -111,16 +112,17 @@
      * @param reportId Report Id.
      * @param data Report data.
      */
-    public void onIntrData(byte reportId, byte[] data) {
-        Log.d(TAG, "onIntrData: reportId=" + reportId);
+    public void onIntrData(BluetoothDevice device, byte reportId, byte[] data) {
+        Log.d(TAG, "onIntrData: device=" + device + " reportId=" + reportId);
     }
 
     /**
      * Callback called when Virtual Cable is removed. This can be either due to
-     * {@link BluetoothHidDevice#unplug()} or request from remote side. After
-     * this callback is received connection will be disconnected automatically.
+     * {@link BluetoothHidDevice#unplug(BluetoothDevice)} or request from remote
+     * side. After this callback is received connection will be disconnected
+     * automatically.
      */
-    public void onVirtualCableUnplug() {
-        Log.d(TAG, "onVirtualCableUnplug");
+    public void onVirtualCableUnplug(BluetoothDevice device) {
+        Log.d(TAG, "onVirtualCableUnplug: device=" + device);
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothInputHost.java b/core/java/android/bluetooth/BluetoothInputHost.java
index 129fe7e..68d105f 100644
--- a/core/java/android/bluetooth/BluetoothInputHost.java
+++ b/core/java/android/bluetooth/BluetoothInputHost.java
@@ -27,6 +27,7 @@
 import android.util.Log;
 
 import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -137,28 +138,28 @@
         }
 
         @Override
-        public void onGetReport(byte type, byte id, int bufferSize) {
-            mCallback.onGetReport(type, id, bufferSize);
+        public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) {
+            mCallback.onGetReport(device, type, id, bufferSize);
         }
 
         @Override
-        public void onSetReport(byte type, byte id, byte[] data) {
-            mCallback.onSetReport(type, id, data);
+        public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) {
+            mCallback.onSetReport(device, type, id, data);
         }
 
         @Override
-        public void onSetProtocol(byte protocol) {
-            mCallback.onSetProtocol(protocol);
+        public void onSetProtocol(BluetoothDevice device, byte protocol) {
+            mCallback.onSetProtocol(device, protocol);
         }
 
         @Override
-        public void onIntrData(byte reportId, byte[] data) {
-            mCallback.onIntrData(reportId, data);
+        public void onIntrData(BluetoothDevice device, byte reportId, byte[] data) {
+            mCallback.onIntrData(device, reportId, data);
         }
 
         @Override
-        public void onVirtualCableUnplug() {
-            mCallback.onVirtualCableUnplug();
+        public void onVirtualCableUnplug(BluetoothDevice device) {
+            mCallback.onVirtualCableUnplug(device);
         }
     }
 
@@ -276,21 +277,59 @@
         mServiceListener = null;
     }
 
-    @Override
+    /**
+     * {@inheritDoc}
+     */
     public List<BluetoothDevice> getConnectedDevices() {
         Log.v(TAG, "getConnectedDevices()");
-        return null;
+
+        if (mService != null) {
+            try {
+                return mService.getConnectedDevices();
+            } catch (RemoteException e) {
+                Log.e(TAG, e.toString());
+            }
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+
+        return new ArrayList<BluetoothDevice>();
     }
 
-    @Override
+    /**
+     * {@inheritDoc}
+     */
     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
         Log.v(TAG, "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states));
-        return null;
+
+        if (mService != null) {
+            try {
+                return mService.getDevicesMatchingConnectionStates(states);
+            } catch (RemoteException e) {
+                Log.e(TAG, e.toString());
+            }
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+
+        return new ArrayList<BluetoothDevice>();
     }
 
-    @Override
+    /**
+     * {@inheritDoc}
+     */
     public int getConnectionState(BluetoothDevice device) {
-        Log.v(TAG, "getConnectionState(): device=" + device.getAddress());
+        Log.v(TAG, "getConnectionState(): device=" + device);
+
+        if (mService != null) {
+            try {
+                return mService.getConnectionState(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, e.toString());
+            }
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+        }
 
         return STATE_DISCONNECTED;
     }
@@ -379,14 +418,12 @@
      * @param data Report data, not including Report Id.
      * @return
      */
-    public boolean sendReport(int id, byte[] data) {
-        Log.v(TAG, "sendReport(): id=" + id);
-
+    public boolean sendReport(BluetoothDevice device, int id, byte[] data) {
         boolean result = false;
 
         if (mService != null) {
             try {
-                result = mService.sendReport(id, data);
+                result = mService.sendReport(device, id, data);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
             }
@@ -399,21 +436,21 @@
 
     /**
      * Sends report to remote host as reply for GET_REPORT request from
-     * {@link BluetoothHidDeviceCallback#onGetReport(byte, byte, int)}.
+     * {@link BluetoothHidDeviceCallback#onGetReport(BluetoothDevice, byte, byte, int)}.
      *
      * @param type Report Type, as in request.
      * @param id Report Id, as in request.
      * @param data Report data, not including Report Id.
      * @return
      */
-    public boolean replyReport(byte type, byte id, byte[] data) {
-        Log.v(TAG, "replyReport(): type=" + type + " id=" + id);
+    public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) {
+        Log.v(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id);
 
         boolean result = false;
 
         if (mService != null) {
             try {
-                result = mService.replyReport(type, id, data);
+                result = mService.replyReport(device, type, id, data);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
             }
@@ -426,19 +463,19 @@
 
     /**
      * Sends error handshake message as reply for invalid SET_REPORT request
-     * from {@link BluetoothHidDeviceCallback#onSetReport(byte, byte, byte[])}.
+     * from {@link BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])}.
      *
      * @param error Error to be sent for SET_REPORT via HANDSHAKE.
      * @return
      */
-    public boolean reportError(byte error) {
-        Log.v(TAG, "reportError(): error = " + error);
+    public boolean reportError(BluetoothDevice device, byte error) {
+        Log.v(TAG, "reportError(): device=" + device + " error=" + error);
 
         boolean result = false;
 
         if (mService != null) {
             try {
-                result = mService.reportError(error);
+                result = mService.reportError(device, error);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
             }
@@ -454,14 +491,14 @@
      *
      * @return
      */
-    public boolean unplug() {
-        Log.v(TAG, "unplug()");
+    public boolean unplug(BluetoothDevice device) {
+        Log.v(TAG, "unplug(): device=" + device);
 
         boolean result = false;
 
         if (mService != null) {
             try {
-                result = mService.unplug();
+                result = mService.unplug(device);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
             }
@@ -478,14 +515,14 @@
      *
      * @return
      */
-    public boolean connect() {
-        Log.v(TAG, "connect()");
+    public boolean connect(BluetoothDevice device) {
+        Log.v(TAG, "connect(): device=" + device);
 
         boolean result = false;
 
         if (mService != null) {
             try {
-                result = mService.connect();
+                result = mService.connect(device);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
             }
@@ -501,14 +538,14 @@
      *
      * @return
      */
-    public boolean disconnect() {
-        Log.v(TAG, "disconnect()");
+    public boolean disconnect(BluetoothDevice device) {
+        Log.v(TAG, "disconnect(): device=" + device);
 
         boolean result = false;
 
         if (mService != null) {
             try {
-                result = mService.disconnect();
+                result = mService.disconnect(device);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
             }
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index b686938..98a5341 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -243,7 +243,7 @@
         }
 
         as.mPfd = new ParcelFileDescriptor(fds[0]);
-        as.mSocket = new LocalSocket(fds[0]);
+        as.mSocket = LocalSocket.createConnectedLocalSocket(fds[0]);
         as.mSocketIS = as.mSocket.getInputStream();
         as.mSocketOS = as.mSocket.getOutputStream();
         as.mAddress = RemoteAddr;
@@ -367,7 +367,7 @@
                 if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
                 if (mPfd == null) throw new IOException("bt socket connect failed");
                 FileDescriptor fd = mPfd.getFileDescriptor();
-                mSocket = new LocalSocket(fd);
+                mSocket = LocalSocket.createConnectedLocalSocket(fd);
                 mSocketIS = mSocket.getInputStream();
                 mSocketOS = mSocket.getOutputStream();
             }
@@ -416,9 +416,9 @@
                 if(mSocketState != SocketState.INIT) return EBADFD;
                 if(mPfd == null) return -1;
                 FileDescriptor fd = mPfd.getFileDescriptor();
-                if (DBG) Log.d(TAG, "bindListen(), new LocalSocket ");
-                mSocket = new LocalSocket(fd);
-                if (DBG) Log.d(TAG, "bindListen(), new LocalSocket.getInputStream() ");
+                if (DBG) Log.d(TAG, "bindListen(), Create LocalSocket");
+                mSocket = LocalSocket.createConnectedLocalSocket(fd);
+                if (DBG) Log.d(TAG, "bindListen(), new LocalSocket.getInputStream()");
                 mSocketIS = mSocket.getInputStream();
                 mSocketOS = mSocket.getOutputStream();
             }
diff --git a/core/java/android/bluetooth/IBluetoothA2dp.aidl b/core/java/android/bluetooth/IBluetoothA2dp.aidl
index 26ff9e27..5b524eb 100644
--- a/core/java/android/bluetooth/IBluetoothA2dp.aidl
+++ b/core/java/android/bluetooth/IBluetoothA2dp.aidl
@@ -16,6 +16,7 @@
 
 package android.bluetooth;
 
+import android.bluetooth.BluetoothCodecConfig;
 import android.bluetooth.BluetoothDevice;
 
 /**
@@ -36,4 +37,6 @@
     oneway void adjustAvrcpAbsoluteVolume(int direction);
     oneway void setAvrcpAbsoluteVolume(int volume);
     boolean isA2dpPlaying(in BluetoothDevice device);
+    BluetoothCodecConfig getCodecConfig();
+    oneway void setCodecConfigPreference(in BluetoothCodecConfig codecConfig);
 }
diff --git a/core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl b/core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl
index 1252876..a737198 100644
--- a/core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl
@@ -23,9 +23,9 @@
 interface IBluetoothHidDeviceCallback {
    void onAppStatusChanged(in BluetoothDevice device, in BluetoothHidDeviceAppConfiguration config, boolean registered);
    void onConnectionStateChanged(in BluetoothDevice device, in int state);
-   void onGetReport(in byte type, in byte id, in int bufferSize);
-   void onSetReport(in byte type, in byte id, in byte[] data);
-   void onSetProtocol(in byte protocol);
-   void onIntrData(in byte reportId, in byte[] data);
-   void onVirtualCableUnplug();
+   void onGetReport(in BluetoothDevice device, in byte type, in byte id, in int bufferSize);
+   void onSetReport(in BluetoothDevice device, in byte type, in byte id, in byte[] data);
+   void onSetProtocol(in BluetoothDevice device, in byte protocol);
+   void onIntrData(in BluetoothDevice device, in byte reportId, in byte[] data);
+   void onVirtualCableUnplug(in BluetoothDevice device);
 }
diff --git a/core/java/android/bluetooth/IBluetoothInputHost.aidl b/core/java/android/bluetooth/IBluetoothInputHost.aidl
index b2c421c..6c4993f 100644
--- a/core/java/android/bluetooth/IBluetoothInputHost.aidl
+++ b/core/java/android/bluetooth/IBluetoothInputHost.aidl
@@ -28,10 +28,13 @@
             in BluetoothHidDeviceAppSdpSettings sdp, in BluetoothHidDeviceAppQosSettings inQos,
             in BluetoothHidDeviceAppQosSettings outQos, in IBluetoothHidDeviceCallback callback);
     boolean unregisterApp(in BluetoothHidDeviceAppConfiguration config);
-    boolean sendReport(in int id, in byte[] data);
-    boolean replyReport(in byte type, in byte id, in byte[] data);
-    boolean reportError(byte error);
-    boolean unplug();
-    boolean connect();
-    boolean disconnect();
+    boolean sendReport(in BluetoothDevice device, in int id, in byte[] data);
+    boolean replyReport(in BluetoothDevice device, in byte type, in byte id, in byte[] data);
+    boolean reportError(in BluetoothDevice device, byte error);
+    boolean unplug(in BluetoothDevice device);
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index fd11031..02b86fe 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2768,6 +2768,9 @@
      *  connectivity.  On releases before NYC, it should only be obtained from an application
      *  context, and not from any other derived context to avoid memory leaks within the calling
      *  process.
+     *  <dt> {@link #WIFI_AWARE_SERVICE} ("wifiaware")
+     *  <dd> A {@link android.net.wifi.aware.WifiAwareManager WifiAwareManager} for management of
+     * Wi-Fi Aware discovery and connectivity.
      *  <dt> {@link #WIFI_P2P_SERVICE} ("wifip2p")
      *  <dd> A {@link android.net.wifi.p2p.WifiP2pManager WifiP2pManager} for management of
      * Wi-Fi Direct connectivity.
@@ -3144,7 +3147,6 @@
      *
      * @see #getSystemService
      * @see android.net.wifi.aware.WifiAwareManager
-     * @hide PROPOSED_AWARE_API
      */
     public static final String WIFI_AWARE_SERVICE = "wifiaware";
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index b0efd89..11e19f3 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2041,8 +2041,6 @@
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device supports Wi-Fi Aware.
-     *
-     * @hide PROPOSED_AWARE_API
      */
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_WIFI_AWARE = "android.hardware.wifi.aware";
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 51431eb..042481f 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -223,6 +223,13 @@
     public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
 
     /**
+     * Key for passing a user agent string to the captive portal login activity.
+     * {@hide}
+     */
+    public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT =
+            "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
+
+    /**
      * Broadcast action to indicate the change of data activity status
      * (idle or active) on a network in a recent period.
      * The network becomes active when data transmission is started, or
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
index 932f031..9573953 100644
--- a/core/java/android/net/INetworkScoreService.aidl
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -100,4 +100,21 @@
      * @hide
      */
     boolean requestScores(in NetworkKey[] networks);
+
+    /**
+     * Determine whether the application with the given UID is the enabled scorer.
+     *
+     * @param callingUid the UID to check
+     * @return true if the provided UID is the active scorer, false otherwise.
+     * @hide
+     */
+    boolean isCallerActiveScorer(int callingUid);
+
+    /**
+     * Obtain the package name of the current active network scorer.
+     *
+     * @return the full package name of the current active scorer, or null if there is no active
+     *         scorer.
+     */
+    String getActiveScorerPackage();
 }
diff --git a/core/java/android/net/LocalServerSocket.java b/core/java/android/net/LocalServerSocket.java
index 9464222..3fcde330 100644
--- a/core/java/android/net/LocalServerSocket.java
+++ b/core/java/android/net/LocalServerSocket.java
@@ -87,9 +87,9 @@
     {
         LocalSocketImpl acceptedImpl = new LocalSocketImpl();
 
-        impl.accept (acceptedImpl);
+        impl.accept(acceptedImpl);
 
-        return new LocalSocket(acceptedImpl, LocalSocket.SOCKET_UNKNOWN);
+        return LocalSocket.createLocalSocketForAccept(acceptedImpl);
     }
 
     /**
diff --git a/core/java/android/net/LocalSocket.java b/core/java/android/net/LocalSocket.java
index e14facb1..8afa1ed 100644
--- a/core/java/android/net/LocalSocket.java
+++ b/core/java/android/net/LocalSocket.java
@@ -31,6 +31,7 @@
 public class LocalSocket implements Closeable {
 
     private final LocalSocketImpl impl;
+    /** false if impl.create() needs to be called */
     private volatile boolean implCreated;
     private LocalSocketAddress localAddress;
     private boolean isBound;
@@ -61,31 +62,44 @@
      */
     public LocalSocket(int sockType) {
         this(new LocalSocketImpl(), sockType);
-        isBound = false;
-        isConnected = false;
     }
 
-    /**
-     * Creates a AF_LOCAL/UNIX domain stream socket with FileDescriptor.
-     * @hide
-     */
-    public LocalSocket(FileDescriptor fd) throws IOException {
-        this(new LocalSocketImpl(fd), SOCKET_UNKNOWN);
-        isBound = true;
-        isConnected = true;
-    }
-
-    /**
-     * for use with AndroidServerSocket
-     * @param impl a SocketImpl
-     */
-    /*package*/ LocalSocket(LocalSocketImpl impl, int sockType) {
+    private LocalSocket(LocalSocketImpl impl, int sockType) {
         this.impl = impl;
         this.sockType = sockType;
         this.isConnected = false;
         this.isBound = false;
     }
 
+    /**
+     * Creates a LocalSocket instances using the FileDescriptor for an already-connected
+     * AF_LOCAL/UNIX domain stream socket. Note: the FileDescriptor must be closed by the caller:
+     * closing the LocalSocket will not close it.
+     *
+     * @hide - used by BluetoothSocket.
+     */
+    public static LocalSocket createConnectedLocalSocket(FileDescriptor fd) {
+        return createConnectedLocalSocket(new LocalSocketImpl(fd), SOCKET_UNKNOWN);
+    }
+
+    /**
+     * for use with LocalServerSocket.accept()
+     */
+    static LocalSocket createLocalSocketForAccept(LocalSocketImpl impl) {
+        return createConnectedLocalSocket(impl, SOCKET_UNKNOWN);
+    }
+
+    /**
+     * Creates a LocalSocket from an existing LocalSocketImpl that is already connected.
+     */
+    private static LocalSocket createConnectedLocalSocket(LocalSocketImpl impl, int sockType) {
+        LocalSocket socket = new LocalSocket(impl, sockType);
+        socket.isConnected = true;
+        socket.isBound = true;
+        socket.implCreated = true;
+        return socket;
+    }
+
     /** {@inheritDoc} */
     @Override
     public String toString() {
@@ -216,11 +230,11 @@
         implCreateIfNeeded();
         impl.shutdownOutput();
     }
-    
+
     public void setReceiveBufferSize(int size) throws IOException {
         impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size));
     }
-    
+
     public int getReceiveBufferSize() throws IOException {
         return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue();
     }
@@ -228,7 +242,7 @@
     public void setSoTimeout(int n) throws IOException {
         impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(n));
     }
-    
+
     public int getSoTimeout() throws IOException {
         return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue();
     }
@@ -236,7 +250,7 @@
     public void setSendBufferSize(int n) throws IOException {
         impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(n));
     }
-    
+
     public int getSendBufferSize() throws IOException {
         return ((Integer) impl.getOption(SocketOptions.SO_SNDBUF)).intValue();
     }
@@ -321,5 +335,5 @@
      */
     public FileDescriptor getFileDescriptor() {
         return impl.getFileDescriptor();
-    }    
+    }
 }
diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java
index 0f0e9c4..05c8afb 100644
--- a/core/java/android/net/LocalSocketImpl.java
+++ b/core/java/android/net/LocalSocketImpl.java
@@ -218,7 +218,7 @@
      *
      * @param fd non-null; bound file descriptor
      */
-    /*package*/ LocalSocketImpl(FileDescriptor fd) throws IOException
+    /*package*/ LocalSocketImpl(FileDescriptor fd)
     {
         this.fd = fd;
     }
@@ -235,29 +235,29 @@
      * @throws IOException
      */
     public void create(int sockType) throws IOException {
-        // no error if socket already created
-        // need this for LocalServerSocket.accept()
-        if (fd == null) {
-            int osType;
-            switch (sockType) {
-                case LocalSocket.SOCKET_DGRAM:
-                    osType = OsConstants.SOCK_DGRAM;
-                    break;
-                case LocalSocket.SOCKET_STREAM:
-                    osType = OsConstants.SOCK_STREAM;
-                    break;
-                case LocalSocket.SOCKET_SEQPACKET:
-                    osType = OsConstants.SOCK_SEQPACKET;
-                    break;
-                default:
-                    throw new IllegalStateException("unknown sockType");
-            }
-            try {
-                fd = Os.socket(OsConstants.AF_UNIX, osType, 0);
-                mFdCreatedInternally = true;
-            } catch (ErrnoException e) {
-                e.rethrowAsIOException();
-            }
+        if (fd != null) {
+            throw new IOException("LocalSocketImpl already has an fd");
+        }
+
+        int osType;
+        switch (sockType) {
+            case LocalSocket.SOCKET_DGRAM:
+                osType = OsConstants.SOCK_DGRAM;
+                break;
+            case LocalSocket.SOCKET_STREAM:
+                osType = OsConstants.SOCK_STREAM;
+                break;
+            case LocalSocket.SOCKET_SEQPACKET:
+                osType = OsConstants.SOCK_SEQPACKET;
+                break;
+            default:
+                throw new IllegalStateException("unknown sockType");
+        }
+        try {
+            fd = Os.socket(OsConstants.AF_UNIX, osType, 0);
+            mFdCreatedInternally = true;
+        } catch (ErrnoException e) {
+            e.rethrowAsIOException();
         }
     }
 
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index dacea55..4dd8ce9 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -420,8 +420,6 @@
 
     /**
      * Indicates this network uses a Wi-Fi Aware transport.
-     *
-     * @hide PROPOSED_AWARE_API
      */
     public static final int TRANSPORT_WIFI_AWARE = 5;
 
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 1825956..a6854dc 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -27,7 +27,6 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.UserHandle;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -44,19 +43,11 @@
  * <p>A network scorer is any application which:
  * <ul>
  * <li>Declares the {@link android.Manifest.permission#SCORE_NETWORKS} permission.
- * <li>Includes a receiver for {@link #ACTION_SCORE_NETWORKS} guarded by the
- *     {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission which scores
- *     networks and (eventually) calls {@link #updateScores} with the results. If this receiver
- *     specifies an android:label attribute, this label will be used when referring to the
- *     application throughout system settings; otherwise, the application label will be used.
+ * <li>Include a Service for the {@link #ACTION_RECOMMEND_NETWORKS} action
+ *     protected by the {@link android.Manifest.permission#BIND_NETWORK_RECOMMENDATION_SERVICE}
+ *     permission.
  * </ul>
  *
- * <p>The system keeps track of an active scorer application; at any time, only this application
- * will receive {@link #ACTION_SCORE_NETWORKS} broadcasts and will be permitted to call
- * {@link #updateScores}. Applications may determine the current active scorer with
- * {@link #getActiveScorerPackage()} and request to change the active scorer by sending an
- * {@link #ACTION_CHANGE_ACTIVE} broadcast with another scorer.
- *
  * @hide
  */
 @SystemApi
@@ -179,11 +170,11 @@
      *         scorer.
      */
     public String getActiveScorerPackage() {
-        NetworkScorerAppData app = new NetworkScorerAppManager(mContext).getActiveScorer();
-        if (app == null) {
-            return null;
+        try {
+            return mService.getActiveScorerPackage();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return app.packageName;
     }
 
     /**
@@ -263,12 +254,9 @@
     /**
      * Request scoring for networks.
      *
-     * <p>Note that this is just a helper method to assemble the broadcast, and will run in the
-     * calling process.
-     *
      * @return true if the broadcast was sent, or false if there is no active scorer.
      * @throws SecurityException if the caller does not hold the
-     *         {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
+     *         {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
      * @hide
      */
     public boolean requestScores(NetworkKey[] networks) throws SecurityException {
@@ -285,7 +273,7 @@
      * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
      * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
      * @throws SecurityException if the caller does not hold the
-     *         {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
+     *         {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
      * @throws IllegalArgumentException if a score cache is already registered for this type.
      * @deprecated equivalent to registering for cache updates with CACHE_FILTER_NONE.
      * @hide
@@ -302,7 +290,7 @@
      * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores
      * @param filterType the {@link CacheUpdateFilter} to apply
      * @throws SecurityException if the caller does not hold the
-     *         {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
+     *         {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
      * @throws IllegalArgumentException if a score cache is already registered for this type.
      * @hide
      */
@@ -321,7 +309,7 @@
      * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
      * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
      * @throws SecurityException if the caller does not hold the
-     *         {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
+     *         {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
      * @throws IllegalArgumentException if a score cache is already registered for this type.
      * @hide
      */
@@ -342,7 +330,8 @@
      *                request details
      * @return a {@link RecommendationResult} instance containing the recommended network
      *         to connect to
-     * @throws SecurityException
+     * @throws SecurityException if the caller does not hold the
+     *         {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
      */
     public RecommendationResult requestRecommendation(RecommendationRequest request)
             throws SecurityException {
@@ -352,4 +341,19 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Determine whether the application with the given UID is the enabled scorer.
+     *
+     * @param callingUid the UID to check
+     * @return true if the provided UID is the active scorer, false otherwise.
+     * @hide
+     */
+    public boolean isCallerActiveScorer(int callingUid) {
+        try {
+            return mService.isCallerActiveScorer(callingUid);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
index 4282ca7..23d5af5 100644
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ b/core/java/android/net/NetworkScorerAppManager.java
@@ -16,7 +16,6 @@
 
 package android.net;
 
-import android.Manifest;
 import android.Manifest.permission;
 import android.annotation.Nullable;
 import android.content.ContentResolver;
@@ -28,7 +27,9 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
+
 import com.android.internal.R;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -226,18 +227,13 @@
     }
 
     /** Determine whether the application with the given UID is the enabled scorer. */
+    @Deprecated // Use NetworkScoreManager.isCallerActiveScorer()
     public boolean isCallerActiveScorer(int callingUid) {
         NetworkScorerAppData defaultApp = getActiveScorer();
         if (defaultApp == null) {
             return false;
         }
-        if (callingUid != defaultApp.packageUid) {
-            return false;
-        }
-        // To be extra safe, ensure the caller holds the SCORE_NETWORKS permission. It always
-        // should, since it couldn't become the active scorer otherwise, but this can't hurt.
-        return mContext.checkCallingPermission(Manifest.permission.SCORE_NETWORKS) ==
-                PackageManager.PERMISSION_GRANTED;
+        return callingUid == defaultApp.packageUid;
     }
 
     private boolean isNetworkRecommendationsDisabled() {
diff --git a/core/java/android/net/RecommendationRequest.java b/core/java/android/net/RecommendationRequest.java
index a96f90d..d013f64 100644
--- a/core/java/android/net/RecommendationRequest.java
+++ b/core/java/android/net/RecommendationRequest.java
@@ -41,6 +41,7 @@
      * Builder class for constructing {@link RecommendationRequest} instances.
      * @hide
      */
+    @SystemApi
     public static final class Builder {
         private ScanResult[] mScanResults;
         private WifiConfiguration mCurrentConfig;
diff --git a/core/java/android/net/ScoredNetwork.java b/core/java/android/net/ScoredNetwork.java
index 94e5187..7e3dd77 100644
--- a/core/java/android/net/ScoredNetwork.java
+++ b/core/java/android/net/ScoredNetwork.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Bundle;
@@ -24,6 +25,8 @@
 
 import java.lang.Math;
 import java.lang.UnsupportedOperationException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
@@ -33,6 +36,15 @@
  */
 @SystemApi
 public class ScoredNetwork implements Parcelable {
+
+  /**
+     * Key used with the {@link #attributes} bundle to define the badging curve.
+     *
+     * <p>The badging curve is a {@link RssiCurve} used to map different RSSI values to {@link
+     * Badging} enums.
+     */
+    public static final String ATTRIBUTES_KEY_BADGING_CURVE =
+            "android.net.attributes.key.BADGING_CURVE";
     /**
      * Extra used with {@link #attributes} to specify whether the
      * network is believed to have a captive portal.
@@ -58,6 +70,15 @@
     public static final String ATTRIBUTES_KEY_RANKING_SCORE_OFFSET =
             "android.net.attributes.key.RANKING_SCORE_OFFSET";
 
+    @IntDef({BADGING_NONE, BADGING_SD, BADGING_HD, BADGING_4K})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Badging {}
+
+    public static final int BADGING_NONE = 0;
+    public static final int BADGING_SD = 10;
+    public static final int BADGING_HD = 20;
+    public static final int BADGING_4K = 30;
+
     /** A {@link NetworkKey} uniquely identifying this network. */
     public final NetworkKey networkKey;
 
@@ -249,6 +270,25 @@
         }
     }
 
+    /**
+     * Return the {@link Badging} enum for this network for the given RSSI, derived from the
+     * badging curve.
+     *
+     * <p>If no badging curve is present, {@link #BADGE_NONE} will be returned.
+     *
+     * @param rssi The rssi level for which the badge should be calculated
+     */
+    @Badging
+    public int calculateBadge(int rssi) {
+        if (attributes != null && attributes.containsKey(ATTRIBUTES_KEY_BADGING_CURVE)) {
+            RssiCurve badgingCurve =
+                    attributes.getParcelable(ATTRIBUTES_KEY_BADGING_CURVE);
+            return badgingCurve.lookupScore(rssi);
+        }
+
+        return BADGING_NONE;
+    }
+
     public static final Parcelable.Creator<ScoredNetwork> CREATOR =
             new Parcelable.Creator<ScoredNetwork>() {
                 @Override
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 151239b..f6edee0 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -783,7 +783,7 @@
      */
     public static boolean isBuildConsistent() {
         // Don't care on eng builds.  Incremental build may trigger false negative.
-        if ("eng".equals(TYPE)) return true;
+        if (IS_ENG) return true;
 
         final String system = SystemProperties.get("ro.build.fingerprint");
         final String vendor = SystemProperties.get("ro.vendor.build.fingerprint");
@@ -847,6 +847,10 @@
     public static final boolean IS_DEBUGGABLE =
             SystemProperties.getInt("ro.debuggable", 0) == 1;
 
+    /** {@hide} */
+    public static final boolean IS_ENG =
+            "eng".equals(getString("ro.build.type"));
+
     /**
      * Specifies whether the permissions needed by a legacy app should be
      * reviewed before any of its components can run. A legacy app is one
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index 481b2dc..e025494 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -17,6 +17,7 @@
 package android.os;
 
 import java.util.ArrayList;
+import java.util.NoSuchElementException;
 import libcore.util.NativeAllocationRegistry;
 
 /** @hide */
@@ -33,19 +34,24 @@
                 mNativeContext);
     }
 
+    @Override
     public final native void transact(
-            int code, HwParcel request, HwParcel reply, int flags);
+            int code, HwParcel request, HwParcel reply, int flags)
+        throws RemoteException;
 
     public abstract void onTransact(
-            int code, HwParcel request, HwParcel reply, int flags);
+            int code, HwParcel request, HwParcel reply, int flags)
+        throws RemoteException;
 
     public native final void registerService(
             ArrayList<String> interfaceChain,
-            String serviceName);
+            String serviceName)
+        throws RemoteException;
 
     public static native final IHwBinder getService(
             String iface,
-            String serviceName);
+            String serviceName)
+        throws RemoteException, NoSuchElementException;
 
     // Returns address of the "freeFunction".
     private static native final long native_init();
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index c7612d1..a265dd0 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -212,7 +212,7 @@
     public native final HwBlob readBuffer();
 
     public native final HwBlob readEmbeddedBuffer(
-            long parentHandle, long offset);
+            long parentHandle, long offset, boolean nullable);
 
     public native final void writeBuffer(HwBlob blob);
 
diff --git a/core/java/android/os/HwRemoteBinder.java b/core/java/android/os/HwRemoteBinder.java
index e617e0a..2f89ce6 100644
--- a/core/java/android/os/HwRemoteBinder.java
+++ b/core/java/android/os/HwRemoteBinder.java
@@ -32,12 +32,15 @@
                 mNativeContext);
     }
 
+    @Override
     public IHwInterface queryLocalInterface(String descriptor) {
         return null;
     }
 
+    @Override
     public native final void transact(
-            int code, HwParcel request, HwParcel reply, int flags);
+            int code, HwParcel request, HwParcel reply, int flags)
+        throws RemoteException;
 
     public native boolean linkToDeath(DeathRecipient recipient, long cookie);
     public native boolean unlinkToDeath(DeathRecipient recipient);
diff --git a/core/java/android/os/IHwBinder.java b/core/java/android/os/IHwBinder.java
index f93bfd7..619f4dc 100644
--- a/core/java/android/os/IHwBinder.java
+++ b/core/java/android/os/IHwBinder.java
@@ -23,7 +23,8 @@
     public static final int FLAG_ONEWAY = 1;
 
     public void transact(
-            int code, HwParcel request, HwParcel reply, int flags);
+            int code, HwParcel request, HwParcel reply, int flags)
+        throws RemoteException;
 
     public IHwInterface queryLocalInterface(String descriptor);
 
@@ -36,6 +37,5 @@
     }
 
     public boolean linkToDeath(DeathRecipient recipient, long cookie);
-
     public boolean unlinkToDeath(DeathRecipient recipient);
 }
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 1c3d6bd..dbe2f6d 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -312,11 +312,6 @@
      */
     void setDnsConfigurationForNetwork(int netId, in String[] servers, String domains);
 
-    /**
-     * Bind name servers to a network in the DNS resolver.
-     */
-    void setDnsServersForNetwork(int netId, in String[] servers, String domains);
-
     void setFirewallEnabled(boolean enabled);
     boolean isFirewallEnabled();
     void setFirewallInterfaceRule(String iface, boolean allow);
diff --git a/core/java/android/os/IRecoverySystem.aidl b/core/java/android/os/IRecoverySystem.aidl
index c5ceecd..1ee83ae 100644
--- a/core/java/android/os/IRecoverySystem.aidl
+++ b/core/java/android/os/IRecoverySystem.aidl
@@ -25,5 +25,5 @@
     boolean uncrypt(in String packageFile, IRecoverySystemProgressListener listener);
     boolean setupBcb(in String command);
     boolean clearBcb();
-    void rebootRecoveryWithCommand(in String command);
+    void rebootRecoveryWithCommand(in String command, in boolean update);
 }
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 9cd1a42..d6688e3 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -184,6 +184,11 @@
      */
     public static final int LAST_SHARED_APPLICATION_GID = 59999;
 
+    /** {@hide} */
+    public static final int FIRST_APPLICATION_CACHE_GID = 20000;
+    /** {@hide} */
+    public static final int LAST_APPLICATION_CACHE_GID = 29999;
+
     /**
      * Standard priority of application threads.
      * Use with {@link #setThreadPriority(int)} and
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index d48431a..7f9ea438 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -491,15 +491,10 @@
                 command += securityArg;
             }
 
+            // RECOVERY_SERVICE writes to BCB (bootloader control block) and triggers the reboot.
             RecoverySystem rs = (RecoverySystem) context.getSystemService(
                     Context.RECOVERY_SERVICE);
-            if (!rs.setupBcb(command)) {
-                throw new IOException("Setup BCB failed");
-            }
-
-            // Having set up the BCB (bootloader control block), go ahead and reboot
-            PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-            pm.reboot(PowerManager.REBOOT_RECOVERY_UPDATE);
+            rs.rebootRecoveryWithCommand(command, true /* update */);
 
             throw new IOException("Reboot failed (no permissions?)");
         }
@@ -713,7 +708,7 @@
         // Write the command into BCB (bootloader control block) and boot from
         // there. Will not return unless failed.
         RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
-        rs.rebootRecoveryWithCommand(command.toString());
+        rs.rebootRecoveryWithCommand(command.toString(), false);
 
         throw new IOException("Reboot failed (no permissions?)");
     }
@@ -913,9 +908,9 @@
      * Talks to RecoverySystemService via Binder to set up the BCB command and
      * reboot into recovery accordingly.
      */
-    private void rebootRecoveryWithCommand(String command) {
+    private void rebootRecoveryWithCommand(String command, boolean update) {
         try {
-            mService.rebootRecoveryWithCommand(command);
+            mService.rebootRecoveryWithCommand(command, update);
         } catch (RemoteException ignored) {
         }
     }
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index b3f4453..535a05a 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -213,6 +213,15 @@
     }
 
     /**
+     * Returns the cache GID for a given UID or appId.
+     * @hide
+     */
+    public static int getCacheAppGid(int id) {
+        return Process.FIRST_APPLICATION_CACHE_GID + (id % PER_USER_RANGE)
+                - Process.FIRST_APPLICATION_UID;
+    }
+
+    /**
      * Generate a text representation of the uid, breaking out its individual
      * components -- user, app, isolated, etc.
      * @hide
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index c5507b9..9252887 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -40,6 +40,7 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -49,6 +50,7 @@
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.lang.ref.WeakReference;
@@ -930,24 +932,38 @@
     }
 
     /** {@hide} */
-    public long getPrimaryStorageSize() {
+    public static Pair<String, Long> getPrimaryStoragePathAndSize() {
         for (String path : INTERNAL_STORAGE_SIZE_PATHS) {
             final long numberBlocks = readLong(path);
             if (numberBlocks > 0) {
-                return numberBlocks * INTERNAL_STORAGE_SECTOR_SIZE;
+                return new Pair<>(path, Long.valueOf(numberBlocks * INTERNAL_STORAGE_SECTOR_SIZE));
             }
         }
-        return 0;
+        return null;
     }
 
-    private long readLong(String path) {
+
+    /** {@hide} */
+    public long getPrimaryStorageSize() {
+        final Pair<String, Long> pair = getPrimaryStoragePathAndSize();
+        return pair == null ? 0 : pair.second.longValue();
+    }
+
+    private static long readLong(String path) {
         try (final FileInputStream fis = new FileInputStream(path);
                 final BufferedReader reader = new BufferedReader(new InputStreamReader(fis));) {
             return Long.parseLong(reader.readLine());
-        } catch (Exception e) {
-            Slog.w(TAG, "Could not read " + path, e);
+        } catch (FileNotFoundException e) {
+            // This is expected since we are trying to parse multiple paths.
+            Slog.i(TAG, "readLong(): Path doesn't exist: " + path + ": " + e);
             return 0;
-        }
+        } catch (NumberFormatException e) {
+            Slog.e(TAG, "readLong(): Could not parse " + path + ": " + e);
+            return 0;
+        } catch (Exception e) {
+            Slog.e(TAG, "readLong(): Unknown exception while opening " + path + ": " + e);
+            return 0;
+       }
     }
 
     /** @removed */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e52983e..3ea5dcb 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6498,7 +6498,8 @@
             QS_TILES,
             DOZE_ENABLED,
             DOZE_PULSE_ON_PICK_UP,
-            DOZE_PULSE_ON_DOUBLE_TAP
+            DOZE_PULSE_ON_DOUBLE_TAP,
+            NFC_PAYMENT_DEFAULT_COMPONENT
         };
 
         /**
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index 6196a97..dd45cd0 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -58,7 +58,7 @@
         private final ByteBuffer mBuffer;
 
         // Layout of event log entry received from Android logger.
-        //  see system/core/include/log/logger.h
+        //  see system/core/include/log/log.h
         private static final int LENGTH_OFFSET = 0;
         private static final int HEADER_SIZE_OFFSET = 2;
         private static final int PROCESS_OFFSET = 4;
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 2e0729b..67196ca 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -75,17 +75,6 @@
     private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache";
 
     /**
-     * System property used to enable or disable dirty regions invalidation.
-     * This property is only queried if {@link #RENDER_DIRTY_REGIONS} is true.
-     * The default value of this property is assumed to be true.
-     *
-     * Possible values:
-     * "true", to enable partial invalidates
-     * "false", to disable partial invalidates
-     */
-    static final String RENDER_DIRTY_REGIONS_PROPERTY = "debug.hwui.render_dirty_regions";
-
-    /**
      * System property used to enable or disable hardware rendering profiling.
      * The default value of this property is assumed to be false.
      *
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index e0d589a..2d6f443 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -24,6 +24,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -38,70 +40,104 @@
     private static final String WEBVIEW_ZYGOTE_SERVICE_32 = "webview_zygote32";
     private static final String WEBVIEW_ZYGOTE_SERVICE_64 = "webview_zygote64";
 
+    /**
+     * Lock object that protects all other static members.
+     */
+    private static final Object sLock = new Object();
+
+    /**
+     * Instance that maintains the socket connection to the zygote. This is null if the zygote
+     * is not running or is not connected.
+     */
+    @GuardedBy("sLock")
     private static ZygoteProcess sZygote;
 
+    /**
+     * Information about the selected WebView package. This is set from #onWebViewProviderChanged().
+     */
+    @GuardedBy("sLock")
     private static PackageInfo sPackage;
 
+    /**
+     * Flag for whether multi-process WebView is enabled. If this is false, the zygote
+     * will not be started.
+     */
+    @GuardedBy("sLock")
     private static boolean sMultiprocessEnabled = false;
 
     public static ZygoteProcess getProcess() {
-        connectToZygoteIfNeeded();
-        return sZygote;
+        synchronized (sLock) {
+            connectToZygoteIfNeededLocked();
+            return sZygote;
+        }
     }
 
     public static String getPackageName() {
-        return sPackage.packageName;
+        synchronized (sLock) {
+            return sPackage.packageName;
+        }
     }
 
     public static boolean isMultiprocessEnabled() {
-        return sMultiprocessEnabled && sPackage != null;
+        synchronized (sLock) {
+            return sMultiprocessEnabled && sPackage != null;
+        }
     }
 
     public static void setMultiprocessEnabled(boolean enabled) {
-        sMultiprocessEnabled = enabled;
+        synchronized (sLock) {
+            sMultiprocessEnabled = enabled;
 
-        // When toggling between multi-process being on/off, start or stop the
-        // service. If it is enabled and the zygote is not yet started, bring up the service.
-        // Otherwise, bring down the service. The name may be null if the package
-        // information has not yet been resolved.
-        final String serviceName = getServiceName();
-        if (serviceName == null) return;
+            // When toggling between multi-process being on/off, start or stop the
+            // service. If it is enabled and the zygote is not yet started, bring up the service.
+            // Otherwise, bring down the service. The name may be null if the package
+            // information has not yet been resolved.
+            final String serviceName = getServiceNameLocked();
+            if (serviceName == null) return;
 
-        if (enabled && sZygote == null) {
-            SystemService.start(serviceName);
-        } else {
-            SystemService.stop(serviceName);
-            sZygote = null;
+            if (enabled && sZygote == null) {
+                SystemService.start(serviceName);
+            } else {
+                SystemService.stop(serviceName);
+                sZygote = null;
+            }
         }
     }
 
     public static void onWebViewProviderChanged(PackageInfo packageInfo) {
-        sPackage = packageInfo;
+        String serviceName;
+        synchronized (sLock) {
+            sPackage = packageInfo;
 
-        // If multi-process is not enabled, then do not start the zygote service.
-        if (!sMultiprocessEnabled) {
-            return;
+            // If multi-process is not enabled, then do not start the zygote service.
+            if (!sMultiprocessEnabled) {
+                return;
+            }
+
+            serviceName = getServiceNameLocked();
+            sZygote = null;
+
+            // The service may enter the RUNNING state before it opens the socket,
+            // so connectToZygoteIfNeededLocked() may still fail.
+            if (SystemService.isStopped(serviceName)) {
+                SystemService.start(serviceName);
+            } else {
+                SystemService.restart(serviceName);
+            }
+
+            try {
+                SystemService.waitForState(serviceName, SystemService.State.RUNNING, 5000);
+            } catch (TimeoutException e) {
+                Log.e(LOGTAG, "Timed out waiting for " + serviceName);
+                return;
+            }
+
+            connectToZygoteIfNeededLocked();
         }
-
-        final String serviceName = getServiceName();
-
-        if (SystemService.isStopped(serviceName)) {
-            SystemService.start(serviceName);
-        } else if (sZygote != null) {
-            SystemService.restart(serviceName);
-        }
-
-        try {
-            SystemService.waitForState(serviceName, SystemService.State.RUNNING, 5000);
-        } catch (TimeoutException e) {
-            Log.e(LOGTAG, "Timed out waiting for " + serviceName);
-            return;
-        }
-
-        connectToZygoteIfNeeded();
     }
 
-    private static String getServiceName() {
+    @GuardedBy("sLock")
+    private static String getServiceNameLocked() {
         if (sPackage == null)
             return null;
 
@@ -113,7 +149,8 @@
         return WEBVIEW_ZYGOTE_SERVICE_32;
     }
 
-    private static void connectToZygoteIfNeeded() {
+    @GuardedBy("sLock")
+    private static void connectToZygoteIfNeededLocked() {
         if (sZygote != null)
             return;
 
@@ -122,7 +159,7 @@
             return;
         }
 
-        final String serviceName = getServiceName();
+        final String serviceName = getServiceNameLocked();
         if (!SystemService.isRunning(serviceName)) {
             Log.e(LOGTAG, serviceName + " is not running");
             return;
diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java
index d968e3c..a8a5549 100644
--- a/core/java/com/android/internal/os/WebViewZygoteInit.java
+++ b/core/java/com/android/internal/os/WebViewZygoteInit.java
@@ -62,6 +62,9 @@
             ClassLoader loader = ApplicationLoaders.getDefault().createAndCacheWebViewClassLoader(
                     packagePath, libsPath);
 
+            // Add the APK to the Zygote's list of allowed files for children.
+            Zygote.nativeAllowFileAcrossFork(packagePath);
+
             // Once we have the classloader, look up the WebViewFactoryProvider implementation and
             // call preloadInZygote() on it to give it the opportunity to preload the native library
             // and perform any other initialisation work that should be shared among the children.
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index fc0ccb7..e1e0a21 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -85,6 +85,9 @@
      * file descriptor numbers that are to be closed by the child
      * (and replaced by /dev/null) after forking.  An integer value
      * of -1 in any entry in the array means "ignore this one".
+     * @param fdsToIgnore null-ok an array of ints, either null or holding
+     * one or more POSIX file descriptor numbers that are to be ignored
+     * in the file descriptor table check.
      * @param instructionSet null-ok the instruction set to use.
      * @param appDataDir null-ok the data directory of the app.
      *
@@ -93,11 +96,11 @@
      */
     public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
           int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
-          String instructionSet, String appDataDir) {
+          int[] fdsToIgnore, String instructionSet, String appDataDir) {
         VM_HOOKS.preFork();
         int pid = nativeForkAndSpecialize(
                   uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
-                  instructionSet, appDataDir);
+                  fdsToIgnore, instructionSet, appDataDir);
         // Enable tracing as soon as possible for the child process.
         if (pid == 0) {
             Trace.setTracingEnabled(true);
@@ -111,7 +114,7 @@
 
     native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int debugFlags,
           int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
-          String instructionSet, String appDataDir);
+          int[] fdsToIgnore, String instructionSet, String appDataDir);
 
     /**
      * Special method to start the system server process. In addition to the
@@ -153,6 +156,11 @@
             int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
 
     /**
+     * Lets children of the zygote inherit open file descriptors to this path.
+     */
+    native protected static void nativeAllowFileAcrossFork(String path);
+
+    /**
      * Zygote unmount storage space on initializing.
      * This method is called once.
      */
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 44c6e85..ec80303 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -193,11 +193,14 @@
                 rlimits = parsedArgs.rlimits.toArray(intArray2d);
             }
 
+            int[] fdsToIgnore = null;
+
             if (parsedArgs.invokeWith != null) {
                 FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
                 childPipeFd = pipeFds[1];
                 serverPipeFd = pipeFds[0];
                 Os.fcntlInt(childPipeFd, F_SETFD, 0);
+                fdsToIgnore = new int[] { childPipeFd.getInt$(), serverPipeFd.getInt$() };
             }
 
             /**
@@ -230,7 +233,7 @@
 
             pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                     parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
-                    parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
+                    parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
                     parsedArgs.appDataDir);
         } catch (ErrnoException ex) {
             logAndPrintError(newStderr, "Exception creating pipe", ex);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 70e9004..d9d06c5 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -179,6 +179,7 @@
     com_android_internal_util_VirtualRefBasePtr.cpp \
     com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp \
     hwbinder/EphemeralStorage.cpp \
+    fd_utils.cpp \
 
 LOCAL_C_INCLUDES += \
     $(LOCAL_PATH)/include \
diff --git a/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
index aa6348e..dcb7874 100644
--- a/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
+++ b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
@@ -33,7 +33,9 @@
 #include "HarfBuzzNGFaceSkia.h"
 
 #include <stdlib.h>
-#include <cutils/log.h>
+
+#include <log/log.h>
+
 #include <SkPaint.h>
 #include <SkPath.h>
 #include <SkPoint.h>
diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp
index ac82457..59c5be6 100644
--- a/core/jni/android/graphics/pdf/PdfEditor.cpp
+++ b/core/jni/android/graphics/pdf/PdfEditor.cpp
@@ -20,7 +20,7 @@
 
 #include <vector>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <utils/Log.h>
 
 #include "jni.h"
diff --git a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
index ade718b..5e173ca 100644
--- a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
@@ -15,10 +15,11 @@
  */
 #define LOG_TAG "OpenGLRenderer"
 
+#include "android/log.h"
+
 #include "jni.h"
 #include "GraphicsJNI.h"
 #include "core_jni_helpers.h"
-#include "log/log.h"
 
 #include "Animator.h"
 #include "Interpolator.h"
diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp
index 8eb39e1..fbccfd5 100644
--- a/core/jni/android_hardware_location_ContextHubService.cpp
+++ b/core/jni/android_hardware_location_ContextHubService.cpp
@@ -33,6 +33,7 @@
 #include <unordered_map>
 #include <queue>
 
+#include <android-base/macros.h>
 #include <cutils/log.h>
 
 #include "JNIHelp.h"
@@ -704,10 +705,10 @@
     }
 
     jbyteArray jmsg = env->NewByteArray(msgLen);
-    jintArray jheader = env->NewIntArray(sizeof(header));
+    jintArray jheader = env->NewIntArray(arraysize(header));
 
     env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg);
-    env->SetIntArrayRegion(jheader, 0, sizeof(header), (jint *)header);
+    env->SetIntArrayRegion(jheader, 0, arraysize(header), (jint *)header);
 
     ALOGI("Passing msg type %" PRIu32 " from app %" PRIu32 " from hub %" PRIu32,
           header[HEADER_FIELD_MSG_TYPE], header[HEADER_FIELD_APP_INSTANCE],
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 4976002..d30e6eb 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -457,6 +457,18 @@
 }
 
 static jint
+android_media_AudioSystem_handleDeviceConfigChange(JNIEnv *env, jobject thiz, jint device, jstring device_address, jstring device_name)
+{
+    const char *c_address = env->GetStringUTFChars(device_address, NULL);
+    const char *c_name = env->GetStringUTFChars(device_name, NULL);
+    int status = check_AudioSystem_Command(AudioSystem::handleDeviceConfigChange(static_cast <audio_devices_t>(device),
+                                          c_address, c_name));
+    env->ReleaseStringUTFChars(device_address, c_address);
+    env->ReleaseStringUTFChars(device_name, c_name);
+    return (jint) status;
+}
+
+static jint
 android_media_AudioSystem_setPhoneState(JNIEnv *env, jobject thiz, jint state)
 {
     return (jint) check_AudioSystem_Command(AudioSystem::setPhoneState((audio_mode_t) state));
@@ -1757,6 +1769,7 @@
     {"newAudioSessionId",   "()I",      (void *)android_media_AudioSystem_newAudioSessionId},
     {"setDeviceConnectionState", "(IILjava/lang/String;Ljava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
     {"getDeviceConnectionState", "(ILjava/lang/String;)I",  (void *)android_media_AudioSystem_getDeviceConnectionState},
+    {"handleDeviceConfigChange", "(ILjava/lang/String;Ljava/lang/String;)I", (void *)android_media_AudioSystem_handleDeviceConfigChange},
     {"setPhoneState",       "(I)I",     (void *)android_media_AudioSystem_setPhoneState},
     {"setForceUse",         "(II)I",    (void *)android_media_AudioSystem_setForceUse},
     {"getForceUse",         "(I)I",     (void *)android_media_AudioSystem_getForceUse},
diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp
index d6d4310..37b6df1 100644
--- a/core/jni/android_net_LocalSocketImpl.cpp
+++ b/core/jni/android_net_LocalSocketImpl.cpp
@@ -202,9 +202,7 @@
     msg.msg_control = cmsgbuf;
     msg.msg_controllen = sizeof(cmsgbuf);
 
-    do {
-        ret = recvmsg(fd, &msg, MSG_NOSIGNAL);
-    } while (ret < 0 && errno == EINTR);
+    ret = TEMP_FAILURE_RETRY(recvmsg(fd, &msg, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC));
 
     if (ret < 0 && errno == EPIPE) {
         // Treat this as an end of stream
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index dd5f755..d8fbca8 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -16,32 +16,32 @@
 
 #define LOG_TAG "android.os.Debug"
 
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <malloc.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-#include <time.h>
 #include <sys/time.h>
-#include <errno.h>
-#include <assert.h>
-#include <ctype.h>
-#include <malloc.h>
+#include <time.h>
+#include <unistd.h>
 
 #include <iomanip>
 #include <string>
 
-#include "jni.h"
+#include <android-base/stringprintf.h>
+#include <cutils/debugger.h>
+#include <log/log.h>
+#include <utils/misc.h>
+#include <utils/String8.h>
 
-#include "android-base/stringprintf.h"
-#include "cutils/debugger.h"
-#include "cutils/log.h"
 #include "JNIHelp.h"
-#include "memtrack/memtrack.h"
-#include "memunreachable/memunreachable.h"
-#include "utils/misc.h"
-#include "utils/String8.h"
+#include "jni.h"
+#include <memtrack/memtrack.h>
+#include <memunreachable/memunreachable.h>
 
 namespace android
 {
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 95e031b..e653900 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -26,7 +26,7 @@
 #include <JNIHelp.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <android/hidl/base/1.0/IBase.h>
-#include <android/hidl/base/1.0/BpBase.h>
+#include <android/hidl/base/1.0/BpHwBase.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <hidl/ServiceManagement.h>
 #include <hidl/Status.h>
@@ -39,6 +39,8 @@
 using android::AndroidRuntime;
 using android::hardware::hidl_vec;
 using android::hardware::hidl_string;
+template<typename T>
+using Return = android::hardware::Return<T>;
 
 #define PACKAGE_PATH    "android/os"
 #define CLASS_NAME      "HwBinder"
@@ -52,6 +54,8 @@
     jmethodID get;
 } gArrayListMethods;
 
+static jclass gErrorClass;
+
 static struct fields_t {
     jfieldID contextID;
     jmethodID onTransactID;
@@ -144,6 +148,22 @@
             replyObj.get(),
             flags);
 
+    if (env->ExceptionCheck()) {
+        jthrowable excep = env->ExceptionOccurred();
+        env->ExceptionDescribe();
+
+        if (env->IsInstanceOf(excep, gErrorClass)) {
+            /* It's an error */
+            LOG(ERROR) << "Forcefully exiting";
+            exit(1);
+        } else {
+            env->ExceptionClear();
+            LOG(ERROR) << "Uncaught exception!";
+        }
+
+        env->DeleteLocalRef(excep);
+    }
+
     status_t err = OK;
 
     if (!replyContext->wasSent()) {
@@ -239,35 +259,32 @@
     hidl_vec<hidl_string> interfaceChain;
     interfaceChain.setToExternal(strings, numInterfaces, true /* shouldOwn */);
 
-    using android::hidl::manager::V1_0::IServiceManager;
-
     sp<hardware::IBinder> binder = JHwBinder::GetNativeContext(env, thiz);
 
     /* TODO(b/33440494) this is not right */
-    sp<hidl::base::V1_0::IBase> base = new hidl::base::V1_0::BpBase(binder);
+    sp<hidl::base::V1_0::IBase> base = new hidl::base::V1_0::BpHwBase(binder);
 
     auto manager = hardware::defaultServiceManager();
 
     if (manager == nullptr) {
         LOG(ERROR) << "Could not get hwservicemanager.";
-        signalExceptionForError(env, UNKNOWN_ERROR);
+        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
         return;
     }
 
-    bool ok = manager->add(
-                interfaceChain,
-                serviceName,
-                base);
+    Return<bool> ret = manager->add(interfaceChain, serviceName, base);
 
     env->ReleaseStringUTFChars(serviceNameObj, serviceName);
     serviceName = NULL;
 
+    bool ok = ret.isOk() && ret;
+
     if (ok) {
         LOG(INFO) << "Starting thread pool.";
         ::android::hardware::ProcessState::self()->startThreadPool();
     }
 
-    signalExceptionForError(env, (ok ? OK : UNKNOWN_ERROR));
+    signalExceptionForError(env, (ok ? OK : UNKNOWN_ERROR), true /* canThrowRemoteException */);
 }
 
 static jobject JHwBinder_native_getService(
@@ -303,19 +320,18 @@
 
     if (manager == nullptr) {
         LOG(ERROR) << "Could not get hwservicemanager.";
-        signalExceptionForError(env, UNKNOWN_ERROR);
+        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
         return NULL;
     }
 
-    sp<hardware::IBinder> service;
-    manager->get(
-            ifaceName,
-            serviceName,
-            [&service](sp<hidl::base::V1_0::IBase> out) {
-                service = hardware::toBinder<
-                        hidl::base::V1_0::IBase, hidl::base::V1_0::BpBase
-                    >(out);
-            });
+    Return<sp<hidl::base::V1_0::IBase>> ret = manager->get(ifaceName, serviceName);
+
+    if (!ret.isOk()) {
+        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
+    }
+
+    sp<hardware::IBinder> service = hardware::toBinder<
+            hidl::base::V1_0::IBase, hidl::base::V1_0::BpHwBase>(ret);
 
     env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
     ifaceName = NULL;
@@ -356,6 +372,9 @@
     gArrayListMethods.size = GetMethodIDOrDie(env, arrayListClass, "size", "()I");
     gArrayListMethods.get = GetMethodIDOrDie(env, arrayListClass, "get", "(I)Ljava/lang/Object;");
 
+    jclass errorClass = FindClassOrDie(env, "java/lang/Error");
+    gErrorClass = MakeGlobalRefOrDie(env, errorClass);
+
     return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
 }
 
diff --git a/core/jni/android_os_HwBinder.h b/core/jni/android_os_HwBinder.h
index 2ebc381..fa8fe01 100644
--- a/core/jni/android_os_HwBinder.h
+++ b/core/jni/android_os_HwBinder.h
@@ -24,7 +24,7 @@
 
 namespace android {
 
-struct JHwBinder : public hardware::BBinder {
+struct JHwBinder : public hardware::BHwBinder {
     static void InitClass(JNIEnv *env);
 
     static sp<JHwBinder> SetNativeContext(
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index a10d807..1bd2333 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -49,7 +49,7 @@
 
 } gFields;
 
-void signalExceptionForError(JNIEnv *env, status_t err) {
+void signalExceptionForError(JNIEnv *env, status_t err, bool canThrowRemoteException) {
     switch (err) {
         case OK:
             break;
@@ -114,8 +114,13 @@
 
         default:
         {
+            std::stringstream ss;
+            ss << "HwBinder Error: (" << err << ")";
+
             jniThrowException(
-                    env, "java/lang/RuntimeException", "Unknown error");
+                    env,
+                    canThrowRemoteException ? "android/os/RemoteException" : "java/lang/RuntimeException",
+                    ss.str().c_str());
 
             break;
         }
@@ -563,15 +568,16 @@
 
     size_t parentHandle;
 
-    const hidl_string *s = static_cast<const hidl_string *>(
-            parcel->readBuffer(&parentHandle));
+    const hidl_string *s;
+    status_t err = parcel->readBuffer(&parentHandle,
+            reinterpret_cast<const void**>(&s));
 
-    if (s == NULL) {
-        signalExceptionForError(env, UNKNOWN_ERROR);
+    if (err != OK) {
+        signalExceptionForError(env, err);
         return NULL;
     }
 
-    status_t err = ::android::hardware::readEmbeddedFromParcel(
+    err = ::android::hardware::readEmbeddedFromParcel(
             const_cast<hidl_string *>(s),
             *parcel, parentHandle, 0 /* parentOffset */);
 
@@ -588,20 +594,20 @@
         JNIEnv *env, jobject thiz) {                                           \
     hardware::Parcel *parcel =                                                 \
         JHwParcel::GetNativeContext(env, thiz)->getParcel();                   \
-                                                                               \
     size_t parentHandle;                                                       \
                                                                                \
-    const hidl_vec<Type> *vec =                                                \
-        (const hidl_vec<Type> *)parcel->readBuffer(&parentHandle);             \
+    const hidl_vec<Type> *vec;                                                 \
+    status_t err = parcel->readBuffer(&parentHandle,                           \
+            reinterpret_cast<const void**>(&vec));                             \
                                                                                \
-    if (vec == NULL) {                                                         \
-        signalExceptionForError(env, UNKNOWN_ERROR);                           \
+    if (err != OK) {                                                           \
+        signalExceptionForError(env, err);                                     \
         return NULL;                                                           \
     }                                                                          \
                                                                                \
     size_t childHandle;                                                        \
                                                                                \
-    status_t err = ::android::hardware::readEmbeddedFromParcel(                \
+    err = ::android::hardware::readEmbeddedFromParcel(                         \
                 const_cast<hidl_vec<Type> *>(vec),                             \
                 *parcel,                                                       \
                 parentHandle,                                                  \
@@ -633,17 +639,18 @@
 
     size_t parentHandle;
 
-    const hidl_vec<bool> *vec =
-        (const hidl_vec<bool> *)parcel->readBuffer(&parentHandle);
+    const hidl_vec<bool> *vec;
+    status_t err = parcel->readBuffer(&parentHandle,
+            reinterpret_cast<const void**>(&vec));
 
-    if (vec == NULL) {
-        signalExceptionForError(env, UNKNOWN_ERROR);
+    if (err != OK) {
+        signalExceptionForError(env, err);
         return NULL;
     }
 
     size_t childHandle;
 
-    status_t err = ::android::hardware::readEmbeddedFromParcel(
+    err = ::android::hardware::readEmbeddedFromParcel(
                 const_cast<hidl_vec<bool> *>(vec),
                 *parcel,
                 parentHandle,
@@ -696,16 +703,17 @@
 
     size_t parentHandle;
 
-    const string_vec *vec=
-        (const string_vec *)parcel->readBuffer(&parentHandle);
+    const string_vec *vec;
+    status_t err = parcel->readBuffer(&parentHandle,
+            reinterpret_cast<const void **>(&vec));
 
-    if (vec == NULL) {
-        signalExceptionForError(env, UNKNOWN_ERROR);
+    if (err != OK) {
+        signalExceptionForError(env, err);
         return NULL;
     }
 
     size_t childHandle;
-    status_t err = ::android::hardware::readEmbeddedFromParcel(
+    err = ::android::hardware::readEmbeddedFromParcel(
             const_cast<string_vec *>(vec),
             *parcel, parentHandle, 0 /* parentOffset */, &childHandle);
 
@@ -802,9 +810,10 @@
         JHwParcel::GetNativeContext(env, thiz)->getParcel();
 
     size_t handle;
-    const void *ptr = parcel->readBuffer(&handle);
+    const void *ptr;
+    status_t status = parcel->readBuffer(&handle, &ptr);
 
-    if (ptr == nullptr) {
+    if (status != OK) {
         jniThrowException(env, "java/util/NoSuchElementException", NULL);
         return nullptr;
     }
@@ -813,18 +822,24 @@
 }
 
 static jobject JHwParcel_native_readEmbeddedBuffer(
-        JNIEnv *env, jobject thiz, jlong parentHandle, jlong offset) {
+        JNIEnv *env, jobject thiz, jlong parentHandle, jlong offset,
+        jboolean nullable) {
     hardware::Parcel *parcel =
         JHwParcel::GetNativeContext(env, thiz)->getParcel();
 
     size_t childHandle;
 
-    const void *ptr =
-        parcel->readEmbeddedBuffer(&childHandle, parentHandle, offset);
+    const void *ptr;
+    status_t status =
+        parcel->readNullableEmbeddedBuffer(&childHandle, parentHandle, offset,
+                &ptr);
 
-    if (ptr == nullptr) {
+    if (status != OK) {
         jniThrowException(env, "java/util/NoSuchElementException", NULL);
         return 0;
+    } else if (status == OK && !nullable && ptr == nullptr) {
+        jniThrowException(env, "java/lang/NullPointerException", NULL);
+        return 0;
     }
 
     return JHwBlob::NewObject(env, ptr, childHandle);
@@ -935,7 +950,7 @@
     { "readBuffer", "()L" PACKAGE_PATH "/HwBlob;",
         (void *)JHwParcel_native_readBuffer },
 
-    { "readEmbeddedBuffer", "(JJ)L" PACKAGE_PATH "/HwBlob;",
+    { "readEmbeddedBuffer", "(JJZ)L" PACKAGE_PATH "/HwBlob;",
         (void *)JHwParcel_native_readEmbeddedBuffer },
 
     { "writeBuffer", "(L" PACKAGE_PATH "/HwBlob;)V",
diff --git a/core/jni/android_os_HwParcel.h b/core/jni/android_os_HwParcel.h
index 708bbba..f81de9b 100644
--- a/core/jni/android_os_HwParcel.h
+++ b/core/jni/android_os_HwParcel.h
@@ -67,7 +67,7 @@
     DISALLOW_COPY_AND_ASSIGN(JHwParcel);
 };
 
-void signalExceptionForError(JNIEnv *env, status_t err);
+void signalExceptionForError(JNIEnv *env, status_t err, bool canThrowRemoteException = false);
 int register_android_os_HwParcel(JNIEnv *env);
 
 }  // namespace android
diff --git a/core/jni/android_os_HwRemoteBinder.cpp b/core/jni/android_os_HwRemoteBinder.cpp
index 0a7d84d..f2f8e52 100644
--- a/core/jni/android_os_HwRemoteBinder.cpp
+++ b/core/jni/android_os_HwRemoteBinder.cpp
@@ -347,7 +347,7 @@
         JHwParcel::GetNativeContext(env, replyObj)->getParcel();
 
     status_t err = binder->transact(code, *request, reply, flags);
-    signalExceptionForError(env, err);
+    signalExceptionForError(env, err, true /* canThrowRemoteException */);
 }
 
 static jboolean JHwRemoteBinder_linkToDeath(JNIEnv* env, jobject thiz,
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index 30fc47b..dc5ce39 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -19,15 +19,14 @@
 
 #include <inttypes.h>
 
+#include <cutils/trace.h>
+#include <utils/String8.h>
+#include <log/log.h>
+
 #include <JNIHelp.h>
 #include <ScopedUtfChars.h>
 #include <ScopedStringChars.h>
 
-#include <utils/String8.h>
-
-#include <cutils/trace.h>
-#include <cutils/log.h>
-
 namespace android {
 
 static void sanitizeString(String8& utf8Chars) {
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 5559d48..abcd1e7 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -29,19 +29,19 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <utils/Atomic.h>
 #include <binder/IInterface.h>
+#include <binder/IServiceManager.h>
 #include <binder/IPCThreadState.h>
-#include <utils/Log.h>
-#include <utils/SystemClock.h>
-#include <utils/List.h>
-#include <utils/KeyedVector.h>
-#include <log/logger.h>
 #include <binder/Parcel.h>
 #include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
-#include <utils/threads.h>
+#include <log/log.h>
+#include <utils/Atomic.h>
+#include <utils/KeyedVector.h>
+#include <utils/List.h>
+#include <utils/Log.h>
 #include <utils/String8.h>
+#include <utils/SystemClock.h>
+#include <utils/threads.h>
 
 #include <ScopedUtfChars.h>
 #include <ScopedLocalRef.h>
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 3219d59..0b4fbcc 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -18,6 +18,8 @@
 
 #include <log/log_event_list.h>
 
+#include <log/log.h>
+
 #include "JNIHelp.h"
 #include "core_jni_helpers.h"
 #include "jni.h"
diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp
index 7719e31..20dfe78 100644
--- a/core/jni/android_util_Log.cpp
+++ b/core/jni/android_util_Log.cpp
@@ -21,7 +21,7 @@
 #include <android-base/macros.h>
 #include <assert.h>
 #include <cutils/properties.h>
-#include <log/logger.h>               // For LOGGER_ENTRY_MAX_PAYLOAD.
+#include <log/log.h>               // For LOGGER_ENTRY_MAX_PAYLOAD.
 #include <utils/Log.h>
 #include <utils/String8.h>
 
diff --git a/core/jni/android_util_jar_StrictJarFile.cpp b/core/jni/android_util_jar_StrictJarFile.cpp
index 2e31c8b..4f1f926 100644
--- a/core/jni/android_util_jar_StrictJarFile.cpp
+++ b/core/jni/android_util_jar_StrictJarFile.cpp
@@ -20,13 +20,14 @@
 #include <memory>
 #include <string>
 
+#include <log/log.h>
+
 #include "JNIHelp.h"
 #include "JniConstants.h"
 #include "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
 #include "jni.h"
 #include "ziparchive/zip_archive.h"
-#include "cutils/log.h"
 
 namespace android {
 
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index fec8f4e..a32dbad 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -43,6 +43,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include "android-base/logging.h"
 #include <cutils/fs.h>
 #include <cutils/multiuser.h>
 #include <cutils/sched_policy.h>
@@ -56,7 +57,7 @@
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
 #include "ScopedUtfChars.h"
-#include "fd_utils-inl.h"
+#include "fd_utils.h"
 
 #include "nativebridge/native_bridge.h"
 
@@ -440,6 +441,22 @@
 // The list of open zygote file descriptors.
 static FileDescriptorTable* gOpenFdTable = NULL;
 
+static void FillFileDescriptorVector(JNIEnv* env,
+                                     jintArray java_fds,
+                                     std::vector<int>* fds) {
+  CHECK(fds != nullptr);
+  if (java_fds != nullptr) {
+    ScopedIntArrayRO ar(env, java_fds);
+    if (ar.get() == nullptr) {
+      RuntimeAbort(env, __LINE__, "Bad fd array");
+    }
+    fds->reserve(ar.size());
+    for (size_t i = 0; i < ar.size(); ++i) {
+      fds->push_back(ar[i]);
+    }
+  }
+}
+
 // Utility routine to fork zygote and specialize the child process.
 static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
                                      jint debug_flags, jobjectArray javaRlimits,
@@ -447,6 +464,7 @@
                                      jint mount_external,
                                      jstring java_se_info, jstring java_se_name,
                                      bool is_system_server, jintArray fdsToClose,
+                                     jintArray fdsToIgnore,
                                      jstring instructionSet, jstring dataDir) {
   SetSigChldHandler();
 
@@ -457,12 +475,14 @@
   // If this is the first fork for this zygote, create the open FD table.
   // If it isn't, we just need to check whether the list of open files has
   // changed (and it shouldn't in the normal case).
+  std::vector<int> fds_to_ignore;
+  FillFileDescriptorVector(env, fdsToIgnore, &fds_to_ignore);
   if (gOpenFdTable == NULL) {
-    gOpenFdTable = FileDescriptorTable::Create();
+    gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore);
     if (gOpenFdTable == NULL) {
       RuntimeAbort(env, __LINE__, "Unable to construct file descriptor table.");
     }
-  } else if (!gOpenFdTable->Restat()) {
+  } else if (!gOpenFdTable->Restat(fds_to_ignore)) {
     RuntimeAbort(env, __LINE__, "Unable to restat file descriptor table.");
   }
 
@@ -621,7 +641,9 @@
         JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
         jint debug_flags, jobjectArray rlimits,
         jint mount_external, jstring se_info, jstring se_name,
-        jintArray fdsToClose, jstring instructionSet, jstring appDataDir) {
+        jintArray fdsToClose,
+        jintArray fdsToIgnore,
+        jstring instructionSet, jstring appDataDir) {
     jlong capabilities = 0;
 
     // Grant CAP_WAKE_ALARM to the Bluetooth process.
@@ -656,7 +678,7 @@
 
     return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
             rlimits, capabilities, capabilities, mount_external, se_info,
-            se_name, false, fdsToClose, instructionSet, appDataDir);
+            se_name, false, fdsToClose, fdsToIgnore, instructionSet, appDataDir);
 }
 
 static jint com_android_internal_os_Zygote_nativeForkSystemServer(
@@ -667,7 +689,7 @@
                                       debug_flags, rlimits,
                                       permittedCapabilities, effectiveCapabilities,
                                       MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
-                                      NULL, NULL);
+                                      NULL, NULL, NULL);
   if (pid > 0) {
       // The zygote process checks whether the child process has died or not.
       ALOGI("System server process %d has been created", pid);
@@ -684,6 +706,16 @@
   return pid;
 }
 
+static void com_android_internal_os_Zygote_nativeAllowFileAcrossFork(
+        JNIEnv* env, jclass, jstring path) {
+    ScopedUtfChars path_native(env, path);
+    const char* path_cstr = path_native.c_str();
+    if (!path_cstr) {
+        RuntimeAbort(env, __LINE__, "path_cstr == NULL");
+    }
+    FileDescriptorWhitelist::Get()->Allow(path_cstr);
+}
+
 static void com_android_internal_os_Zygote_nativeUnmountStorageOnInit(JNIEnv* env, jclass) {
     // Zygote process unmount root storage space initially before every child processes are forked.
     // Every forked child processes (include SystemServer) only mount their own root storage space
@@ -724,10 +756,12 @@
 
 static const JNINativeMethod gMethods[] = {
     { "nativeForkAndSpecialize",
-      "(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I",
+      "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[ILjava/lang/String;Ljava/lang/String;)I",
       (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
     { "nativeForkSystemServer", "(II[II[[IJJ)I",
       (void *) com_android_internal_os_Zygote_nativeForkSystemServer },
+    { "nativeAllowFileAcrossFork", "(Ljava/lang/String;)V",
+      (void *) com_android_internal_os_Zygote_nativeAllowFileAcrossFork },
     { "nativeUnmountStorageOnInit", "()V",
       (void *) com_android_internal_os_Zygote_nativeUnmountStorageOnInit }
 };
diff --git a/core/jni/fd_utils-inl.h b/core/jni/fd_utils-inl.h
deleted file mode 100644
index b78b8ff..0000000
--- a/core/jni/fd_utils-inl.h
+++ /dev/null
@@ -1,564 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <string>
-#include <unordered_map>
-#include <set>
-#include <vector>
-#include <algorithm>
-
-#include <android-base/strings.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <grp.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-#include <cutils/log.h>
-#include "JNIHelp.h"
-#include "ScopedPrimitiveArray.h"
-
-// Whitelist of open paths that the zygote is allowed to keep open.
-//
-// In addition to the paths listed here, all files ending with
-// ".jar" under /system/framework" are whitelisted. See
-// FileDescriptorInfo::IsWhitelisted for the canonical definition.
-//
-// If the whitelisted path is associated with a regular file or a
-// character device, the file is reopened after a fork with the same
-// offset and mode. If the whilelisted  path is associated with a
-// AF_UNIX socket, the socket will refer to /dev/null after each
-// fork, and all operations on it will fail.
-static const char* kPathWhitelist[] = {
-  "/dev/null",
-  "/dev/socket/zygote",
-  "/dev/socket/zygote_secondary",
-  "/dev/socket/webview_zygote",
-  "/sys/kernel/debug/tracing/trace_marker",
-  "/system/framework/framework-res.apk",
-  "/dev/urandom",
-  "/dev/ion",
-  "/dev/dri/renderD129", // Fixes b/31172436
-};
-
-static const char* kFdPath = "/proc/self/fd";
-
-// Keeps track of all relevant information (flags, offset etc.) of an
-// open zygote file descriptor.
-class FileDescriptorInfo {
- public:
-  // Create a FileDescriptorInfo for a given file descriptor. Returns
-  // |NULL| if an error occurred.
-  static FileDescriptorInfo* createFromFd(int fd) {
-    struct stat f_stat;
-    // This should never happen; the zygote should always have the right set
-    // of permissions required to stat all its open files.
-    if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
-      ALOGE("Unable to stat fd %d : %s", fd, strerror(errno));
-      return NULL;
-    }
-
-    if (S_ISSOCK(f_stat.st_mode)) {
-      std::string socket_name;
-      if (!GetSocketName(fd, &socket_name)) {
-        return NULL;
-      }
-
-      if (!IsWhitelisted(socket_name)) {
-        ALOGE("Socket name not whitelisted : %s (fd=%d)", socket_name.c_str(), fd);
-        return NULL;
-      }
-
-      return new FileDescriptorInfo(fd);
-    }
-
-    // We only handle whitelisted regular files and character devices. Whitelisted
-    // character devices must provide a guarantee of sensible behaviour when
-    // reopened.
-    //
-    // S_ISDIR : Not supported. (We could if we wanted to, but it's unused).
-    // S_ISLINK : Not supported.
-    // S_ISBLK : Not supported.
-    // S_ISFIFO : Not supported. Note that the zygote uses pipes to communicate
-    // with the child process across forks but those should have been closed
-    // before we got to this point.
-    if (!S_ISCHR(f_stat.st_mode) && !S_ISREG(f_stat.st_mode)) {
-      ALOGE("Unsupported st_mode %d", f_stat.st_mode);
-      return NULL;
-    }
-
-    std::string file_path;
-    if (!Readlink(fd, &file_path)) {
-      return NULL;
-    }
-
-    if (!IsWhitelisted(file_path)) {
-      ALOGE("Not whitelisted : %s", file_path.c_str());
-      return NULL;
-    }
-
-    // File descriptor flags : currently on FD_CLOEXEC. We can set these
-    // using F_SETFD - we're single threaded at this point of execution so
-    // there won't be any races.
-    const int fd_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD));
-    if (fd_flags == -1) {
-      ALOGE("Failed fcntl(%d, F_GETFD) : %s", fd, strerror(errno));
-      return NULL;
-    }
-
-    // File status flags :
-    // - File access mode : (O_RDONLY, O_WRONLY...) we'll pass these through
-    //   to the open() call.
-    //
-    // - File creation flags : (O_CREAT, O_EXCL...) - there's not much we can
-    //   do about these, since the file has already been created. We shall ignore
-    //   them here.
-    //
-    // - Other flags : We'll have to set these via F_SETFL. On linux, F_SETFL
-    //   can only set O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK.
-    //   In particular, it can't set O_SYNC and O_DSYNC. We'll have to test for
-    //   their presence and pass them in to open().
-    int fs_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
-    if (fs_flags == -1) {
-      ALOGE("Failed fcntl(%d, F_GETFL) : %s", fd, strerror(errno));
-      return NULL;
-    }
-
-    // File offset : Ignore the offset for non seekable files.
-    const off_t offset = TEMP_FAILURE_RETRY(lseek64(fd, 0, SEEK_CUR));
-
-    // We pass the flags that open accepts to open, and use F_SETFL for
-    // the rest of them.
-    static const int kOpenFlags = (O_RDONLY | O_WRONLY | O_RDWR | O_DSYNC | O_SYNC);
-    int open_flags = fs_flags & (kOpenFlags);
-    fs_flags = fs_flags & (~(kOpenFlags));
-
-    return new FileDescriptorInfo(f_stat, file_path, fd, open_flags, fd_flags, fs_flags, offset);
-  }
-
-  // Checks whether the file descriptor associated with this object
-  // refers to the same description.
-  bool Restat() const {
-    struct stat f_stat;
-    if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
-      return false;
-    }
-
-    return f_stat.st_ino == stat.st_ino && f_stat.st_dev == stat.st_dev;
-  }
-
-  bool ReopenOrDetach() const {
-    if (is_sock) {
-      return DetachSocket();
-    }
-
-    // NOTE: This might happen if the file was unlinked after being opened.
-    // It's a common pattern in the case of temporary files and the like but
-    // we should not allow such usage from the zygote.
-    const int new_fd = TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags));
-
-    if (new_fd == -1) {
-      ALOGE("Failed open(%s, %d) : %s", file_path.c_str(), open_flags, strerror(errno));
-      return false;
-    }
-
-    if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFD, fd_flags)) == -1) {
-      close(new_fd);
-      ALOGE("Failed fcntl(%d, F_SETFD, %x) : %s", new_fd, fd_flags, strerror(errno));
-      return false;
-    }
-
-    if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFL, fs_flags)) == -1) {
-      close(new_fd);
-      ALOGE("Failed fcntl(%d, F_SETFL, %x) : %s", new_fd, fs_flags, strerror(errno));
-      return false;
-    }
-
-    if (offset != -1 && TEMP_FAILURE_RETRY(lseek64(new_fd, offset, SEEK_SET)) == -1) {
-      close(new_fd);
-      ALOGE("Failed lseek64(%d, SEEK_SET) : %s", new_fd, strerror(errno));
-      return false;
-    }
-
-    if (TEMP_FAILURE_RETRY(dup2(new_fd, fd)) == -1) {
-      close(new_fd);
-      ALOGE("Failed dup2(%d, %d) : %s", fd, new_fd, strerror(errno));
-      return false;
-    }
-
-    close(new_fd);
-
-    return true;
-  }
-
-  const int fd;
-  const struct stat stat;
-  const std::string file_path;
-  const int open_flags;
-  const int fd_flags;
-  const int fs_flags;
-  const off_t offset;
-  const bool is_sock;
-
- private:
-  FileDescriptorInfo(int fd) :
-    fd(fd),
-    stat(),
-    open_flags(0),
-    fd_flags(0),
-    fs_flags(0),
-    offset(0),
-    is_sock(true) {
-  }
-
-  FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
-                     int fd_flags, int fs_flags, off_t offset) :
-    fd(fd),
-    stat(stat),
-    file_path(file_path),
-    open_flags(open_flags),
-    fd_flags(fd_flags),
-    fs_flags(fs_flags),
-    offset(offset),
-    is_sock(false) {
-  }
-
-  // Returns true iff. a given path is whitelisted. A path is whitelisted
-  // if it belongs to the whitelist (see kPathWhitelist) or if it's a path
-  // under /system/framework that ends with ".jar" or if it is a system
-  // framework overlay.
-  static bool IsWhitelisted(const std::string& path) {
-    for (size_t i = 0; i < (sizeof(kPathWhitelist) / sizeof(kPathWhitelist[0])); ++i) {
-      if (kPathWhitelist[i] == path) {
-        return true;
-      }
-    }
-
-    static const char* kFrameworksPrefix = "/system/framework/";
-    static const char* kJarSuffix = ".jar";
-    if (android::base::StartsWith(path, kFrameworksPrefix)
-        && android::base::EndsWith(path, kJarSuffix)) {
-      return true;
-    }
-
-    // Whitelist files needed for Runtime Resource Overlay, like these:
-    // /system/vendor/overlay/framework-res.apk
-    // /system/vendor/overlay/PG/android-framework-runtime-resource-overlay.apk
-    // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
-    // /data/resource-cache/system@vendor@overlay@PG@framework-res.apk@idmap
-    static const char* kOverlayDir = "/system/vendor/overlay/";
-    static const char* kApkSuffix = ".apk";
-
-    if (android::base::StartsWith(path, kOverlayDir)
-        && android::base::EndsWith(path, kApkSuffix)
-        && path.find("/../") == std::string::npos) {
-      return true;
-    }
-
-    static const char* kOverlayIdmapPrefix = "/data/resource-cache/";
-    static const char* kOverlayIdmapSuffix = ".apk@idmap";
-    if (android::base::StartsWith(path, kOverlayIdmapPrefix)
-        && android::base::EndsWith(path, kOverlayIdmapSuffix)) {
-      return true;
-    }
-
-    return false;
-  }
-
-  // TODO: Call android::base::Readlink instead of copying the code here.
-  static bool Readlink(const int fd, std::string* result) {
-    char path[64];
-    snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
-
-    // Code copied from android::base::Readlink starts here :
-
-    // Annoyingly, the readlink system call returns EINVAL for a zero-sized buffer,
-    // and truncates to whatever size you do supply, so it can't be used to query.
-    // We could call lstat first, but that would introduce a race condition that
-    // we couldn't detect.
-    // ext2 and ext4 both have PAGE_SIZE limitations, so we assume that here.
-    char buf[4096];
-    ssize_t len = readlink(path, buf, sizeof(buf));
-    if (len == -1) return false;
-
-    result->assign(buf, len);
-    return true;
-  }
-
-  // Returns the locally-bound name of the socket |fd|. Returns true
-  // iff. all of the following hold :
-  //
-  // - the socket's sa_family is AF_UNIX.
-  // - the length of the path is greater than zero (i.e, not an unnamed socket).
-  // - the first byte of the path isn't zero (i.e, not a socket with an abstract
-  //   address).
-  static bool GetSocketName(const int fd, std::string* result) {
-    sockaddr_storage ss;
-    sockaddr* addr = reinterpret_cast<sockaddr*>(&ss);
-    socklen_t addr_len = sizeof(ss);
-
-    if (TEMP_FAILURE_RETRY(getsockname(fd, addr, &addr_len)) == -1) {
-      ALOGE("Failed getsockname(%d) : %s", fd, strerror(errno));
-      return false;
-    }
-
-    if (addr->sa_family != AF_UNIX) {
-      ALOGE("Unsupported socket (fd=%d) with family %d", fd, addr->sa_family);
-      return false;
-    }
-
-    const sockaddr_un* unix_addr = reinterpret_cast<const sockaddr_un*>(&ss);
-
-    size_t path_len = addr_len - offsetof(struct sockaddr_un, sun_path);
-    // This is an unnamed local socket, we do not accept it.
-    if (path_len == 0) {
-      ALOGE("Unsupported AF_UNIX socket (fd=%d) with empty path.", fd);
-      return false;
-    }
-
-    // This is a local socket with an abstract address, we do not accept it.
-    if (unix_addr->sun_path[0] == '\0') {
-      ALOGE("Unsupported AF_UNIX socket (fd=%d) with abstract address.", fd);
-      return false;
-    }
-
-    // If we're here, sun_path must refer to a null terminated filesystem
-    // pathname (man 7 unix). Remove the terminator before assigning it to an
-    // std::string.
-    if (unix_addr->sun_path[path_len - 1] ==  '\0') {
-      --path_len;
-    }
-
-    result->assign(unix_addr->sun_path, path_len);
-    return true;
-  }
-
-  bool DetachSocket() const {
-    const int dev_null_fd = open("/dev/null", O_RDWR);
-    if (dev_null_fd < 0) {
-      ALOGE("Failed to open /dev/null : %s", strerror(errno));
-      return false;
-    }
-
-    if (dup2(dev_null_fd, fd) == -1) {
-      ALOGE("Failed dup2 on socket descriptor %d : %s", fd, strerror(errno));
-      return false;
-    }
-
-    if (close(dev_null_fd) == -1) {
-      ALOGE("Failed close(%d) : %s", dev_null_fd, strerror(errno));
-      return false;
-    }
-
-    return true;
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo);
-};
-
-// A FileDescriptorTable is a collection of FileDescriptorInfo objects
-// keyed by their FDs.
-class FileDescriptorTable {
- public:
-  // Creates a new FileDescriptorTable. This function scans
-  // /proc/self/fd for the list of open file descriptors and collects
-  // information about them. Returns NULL if an error occurs.
-  static FileDescriptorTable* Create() {
-    DIR* d = opendir(kFdPath);
-    if (d == NULL) {
-      ALOGE("Unable to open directory %s: %s", kFdPath, strerror(errno));
-      return NULL;
-    }
-    int dir_fd = dirfd(d);
-    dirent* e;
-
-    std::unordered_map<int, FileDescriptorInfo*> open_fd_map;
-    while ((e = readdir(d)) != NULL) {
-      const int fd = ParseFd(e, dir_fd);
-      if (fd == -1) {
-        continue;
-      }
-
-      FileDescriptorInfo* info = FileDescriptorInfo::createFromFd(fd);
-      if (info == NULL) {
-        if (closedir(d) == -1) {
-          ALOGE("Unable to close directory : %s", strerror(errno));
-        }
-        return NULL;
-      }
-      open_fd_map[fd] = info;
-    }
-
-    if (closedir(d) == -1) {
-      ALOGE("Unable to close directory : %s", strerror(errno));
-      return NULL;
-    }
-    return new FileDescriptorTable(open_fd_map);
-  }
-
-  bool Restat() {
-    std::set<int> open_fds;
-
-    // First get the list of open descriptors.
-    DIR* d = opendir(kFdPath);
-    if (d == NULL) {
-      ALOGE("Unable to open directory %s: %s", kFdPath, strerror(errno));
-      return false;
-    }
-
-    int dir_fd = dirfd(d);
-    dirent* e;
-    while ((e = readdir(d)) != NULL) {
-      const int fd = ParseFd(e, dir_fd);
-      if (fd == -1) {
-        continue;
-      }
-
-      open_fds.insert(fd);
-    }
-
-    if (closedir(d) == -1) {
-      ALOGE("Unable to close directory : %s", strerror(errno));
-      return false;
-    }
-
-    return RestatInternal(open_fds);
-  }
-
-  // Reopens all file descriptors that are contained in the table. Returns true
-  // if all descriptors were successfully re-opened or detached, and false if an
-  // error occurred.
-  bool ReopenOrDetach() {
-    std::unordered_map<int, FileDescriptorInfo*>::const_iterator it;
-    for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) {
-      const FileDescriptorInfo* info = it->second;
-      if (info == NULL || !info->ReopenOrDetach()) {
-        return false;
-      }
-    }
-
-    return true;
-  }
-
- private:
-  FileDescriptorTable(const std::unordered_map<int, FileDescriptorInfo*>& map)
-      : open_fd_map_(map) {
-  }
-
-  bool RestatInternal(std::set<int>& open_fds) {
-    bool error = false;
-
-    // Iterate through the list of file descriptors we've already recorded
-    // and check whether :
-    //
-    // (a) they continue to be open.
-    // (b) they refer to the same file.
-    std::unordered_map<int, FileDescriptorInfo*>::iterator it = open_fd_map_.begin();
-    while (it != open_fd_map_.end()) {
-      std::set<int>::const_iterator element = open_fds.find(it->first);
-      if (element == open_fds.end()) {
-        // The entry from the file descriptor table is no longer in the list
-        // of open files. We warn about this condition and remove it from
-        // the list of FDs under consideration.
-        //
-        // TODO(narayan): This will be an error in a future android release.
-        // error = true;
-        // ALOGW("Zygote closed file descriptor %d.", it->first);
-        it = open_fd_map_.erase(it);
-      } else {
-        // The entry from the file descriptor table is still open. Restat
-        // it and check whether it refers to the same file.
-        const bool same_file = it->second->Restat();
-        if (!same_file) {
-          // The file descriptor refers to a different description. We must
-          // update our entry in the table.
-          delete it->second;
-          it->second = FileDescriptorInfo::createFromFd(*element);
-          if (it->second == NULL) {
-            // The descriptor no longer no longer refers to a whitelisted file.
-            // We flag an error and remove it from the list of files we're
-            // tracking.
-            error = true;
-            it = open_fd_map_.erase(it);
-          } else {
-            // Successfully restatted the file, move on to the next open FD.
-            ++it;
-          }
-        } else {
-          // It's the same file. Nothing to do here. Move on to the next open
-          // FD.
-          ++it;
-        }
-
-        // Finally, remove the FD from the set of open_fds. We do this last because
-        // |element| will not remain valid after a call to erase.
-        open_fds.erase(element);
-      }
-    }
-
-    if (open_fds.size() > 0) {
-      // The zygote has opened new file descriptors since our last inspection.
-      // We warn about this condition and add them to our table.
-      //
-      // TODO(narayan): This will be an error in a future android release.
-      // error = true;
-      // ALOGW("Zygote opened %zd new file descriptor(s).", open_fds.size());
-
-      // TODO(narayan): This code will be removed in a future android release.
-      std::set<int>::const_iterator it;
-      for (it = open_fds.begin(); it != open_fds.end(); ++it) {
-        const int fd = (*it);
-        FileDescriptorInfo* info = FileDescriptorInfo::createFromFd(fd);
-        if (info == NULL) {
-          // A newly opened file is not on the whitelist. Flag an error and
-          // continue.
-          error = true;
-        } else {
-          // Track the newly opened file.
-          open_fd_map_[fd] = info;
-        }
-      }
-    }
-
-    return !error;
-  }
-
-  static int ParseFd(dirent* e, int dir_fd) {
-    char* end;
-    const int fd = strtol(e->d_name, &end, 10);
-    if ((*end) != '\0') {
-      return -1;
-    }
-
-    // Don't bother with the standard input/output/error, they're handled
-    // specially post-fork anyway.
-    if (fd <= STDERR_FILENO || fd == dir_fd) {
-      return -1;
-    }
-
-    return fd;
-  }
-
-  // Invariant: All values in this unordered_map are non-NULL.
-  std::unordered_map<int, FileDescriptorInfo*> open_fd_map_;
-
-  DISALLOW_COPY_AND_ASSIGN(FileDescriptorTable);
-};
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
new file mode 100644
index 0000000..59a536b
--- /dev/null
+++ b/core/jni/fd_utils.cpp
@@ -0,0 +1,567 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fd_utils.h"
+
+#include <algorithm>
+
+#include <fcntl.h>
+#include <grp.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <android-base/strings.h>
+#include <cutils/log.h>
+
+// Static whitelist of open paths that the zygote is allowed to keep open.
+static const char* kPathWhitelist[] = {
+  "/dev/null",
+  "/dev/socket/zygote",
+  "/dev/socket/zygote_secondary",
+  "/dev/socket/webview_zygote",
+  "/sys/kernel/debug/tracing/trace_marker",
+  "/system/framework/framework-res.apk",
+  "/dev/urandom",
+  "/dev/ion",
+  "/dev/dri/renderD129", // Fixes b/31172436
+};
+
+static const char kFdPath[] = "/proc/self/fd";
+
+// static
+FileDescriptorWhitelist* FileDescriptorWhitelist::Get() {
+  if (instance_ == nullptr) {
+    instance_ = new FileDescriptorWhitelist();
+  }
+  return instance_;
+}
+
+bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const {
+  // Check the static whitelist path.
+  for (const auto& whitelist_path : kPathWhitelist) {
+    if (path == whitelist_path)
+      return true;
+  }
+
+  // Check any paths added to the dynamic whitelist.
+  for (const auto& whitelist_path : whitelist_) {
+    if (path == whitelist_path)
+      return true;
+  }
+
+  static const std::string kFrameworksPrefix = "/system/framework/";
+  static const std::string kJarSuffix = ".jar";
+  if (StartsWith(path, kFrameworksPrefix) && EndsWith(path, kJarSuffix)) {
+    return true;
+  }
+
+  // Whitelist files needed for Runtime Resource Overlay, like these:
+  // /system/vendor/overlay/framework-res.apk
+  // /system/vendor/overlay-subdir/pg/framework-res.apk
+  // /vendor/overlay/framework-res.apk
+  // /vendor/overlay/PG/android-framework-runtime-resource-overlay.apk
+  // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
+  // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap
+  // See AssetManager.cpp for more details on overlay-subdir.
+  static const std::string kOverlayDir = "/system/vendor/overlay/";
+  static const std::string kVendorOverlayDir = "/vendor/overlay";
+  static const std::string kOverlaySubdir = "/system/vendor/overlay-subdir/";
+  static const std::string kApkSuffix = ".apk";
+
+  if ((StartsWith(path, kOverlayDir) || StartsWith(path, kOverlaySubdir)
+       || StartsWith(path, kVendorOverlayDir))
+      && EndsWith(path, kApkSuffix)
+      && path.find("/../") == std::string::npos) {
+    return true;
+  }
+
+  static const std::string kOverlayIdmapPrefix = "/data/resource-cache/";
+  static const std::string kOverlayIdmapSuffix = ".apk@idmap";
+  if (StartsWith(path, kOverlayIdmapPrefix) && EndsWith(path, kOverlayIdmapSuffix)
+      && path.find("/../") == std::string::npos) {
+    return true;
+  }
+
+  // All regular files that are placed under this path are whitelisted automatically.
+  static const std::string kZygoteWhitelistPath = "/vendor/zygote_whitelist/";
+  if (StartsWith(path, kZygoteWhitelistPath) && path.find("/../") == std::string::npos) {
+    return true;
+  }
+
+  return false;
+}
+
+FileDescriptorWhitelist::FileDescriptorWhitelist()
+    : whitelist_() {
+}
+
+// TODO: Call android::base::StartsWith instead of copying the code here.
+// static
+bool FileDescriptorWhitelist::StartsWith(const std::string& str,
+                                         const std::string& prefix) {
+  return str.compare(0, prefix.size(), prefix) == 0;
+}
+
+// TODO: Call android::base::EndsWith instead of copying the code here.
+// static
+bool FileDescriptorWhitelist::EndsWith(const std::string& str,
+                                       const std::string& suffix) {
+  if (suffix.size() > str.size()) {
+    return false;
+  }
+
+  return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
+}
+
+FileDescriptorWhitelist* FileDescriptorWhitelist::instance_ = nullptr;
+
+// static
+FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) {
+  struct stat f_stat;
+  // This should never happen; the zygote should always have the right set
+  // of permissions required to stat all its open files.
+  if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
+    ALOGE("Unable to stat fd %d : %s", fd, strerror(errno));
+    return NULL;
+  }
+
+  const FileDescriptorWhitelist* whitelist = FileDescriptorWhitelist::Get();
+
+  if (S_ISSOCK(f_stat.st_mode)) {
+    std::string socket_name;
+    if (!GetSocketName(fd, &socket_name)) {
+      return NULL;
+    }
+
+    if (!whitelist->IsAllowed(socket_name)) {
+      ALOGE("Socket name not whitelisted : %s (fd=%d)", socket_name.c_str(), fd);
+      return NULL;
+    }
+
+    return new FileDescriptorInfo(fd);
+  }
+
+  // We only handle whitelisted regular files and character devices. Whitelisted
+  // character devices must provide a guarantee of sensible behaviour when
+  // reopened.
+  //
+  // S_ISDIR : Not supported. (We could if we wanted to, but it's unused).
+  // S_ISLINK : Not supported.
+  // S_ISBLK : Not supported.
+  // S_ISFIFO : Not supported. Note that the zygote uses pipes to communicate
+  // with the child process across forks but those should have been closed
+  // before we got to this point.
+  if (!S_ISCHR(f_stat.st_mode) && !S_ISREG(f_stat.st_mode)) {
+    ALOGE("Unsupported st_mode %d", f_stat.st_mode);
+    return NULL;
+  }
+
+  std::string file_path;
+  if (!Readlink(fd, &file_path)) {
+    return NULL;
+  }
+
+  if (!whitelist->IsAllowed(file_path)) {
+    ALOGE("Not whitelisted : %s", file_path.c_str());
+    return NULL;
+  }
+
+  // File descriptor flags : currently on FD_CLOEXEC. We can set these
+  // using F_SETFD - we're single threaded at this point of execution so
+  // there won't be any races.
+  const int fd_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD));
+  if (fd_flags == -1) {
+    ALOGE("Failed fcntl(%d, F_GETFD) : %s", fd, strerror(errno));
+    return NULL;
+  }
+
+  // File status flags :
+  // - File access mode : (O_RDONLY, O_WRONLY...) we'll pass these through
+  //   to the open() call.
+  //
+  // - File creation flags : (O_CREAT, O_EXCL...) - there's not much we can
+  //   do about these, since the file has already been created. We shall ignore
+  //   them here.
+  //
+  // - Other flags : We'll have to set these via F_SETFL. On linux, F_SETFL
+  //   can only set O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK.
+  //   In particular, it can't set O_SYNC and O_DSYNC. We'll have to test for
+  //   their presence and pass them in to open().
+  int fs_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
+  if (fs_flags == -1) {
+    ALOGE("Failed fcntl(%d, F_GETFL) : %s", fd, strerror(errno));
+    return NULL;
+  }
+
+  // File offset : Ignore the offset for non seekable files.
+  const off_t offset = TEMP_FAILURE_RETRY(lseek64(fd, 0, SEEK_CUR));
+
+  // We pass the flags that open accepts to open, and use F_SETFL for
+  // the rest of them.
+  static const int kOpenFlags = (O_RDONLY | O_WRONLY | O_RDWR | O_DSYNC | O_SYNC);
+  int open_flags = fs_flags & (kOpenFlags);
+  fs_flags = fs_flags & (~(kOpenFlags));
+
+  return new FileDescriptorInfo(f_stat, file_path, fd, open_flags, fd_flags, fs_flags, offset);
+}
+
+bool FileDescriptorInfo::Restat() const {
+  struct stat f_stat;
+  if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
+    return false;
+  }
+
+  return f_stat.st_ino == stat.st_ino && f_stat.st_dev == stat.st_dev;
+}
+
+bool FileDescriptorInfo::ReopenOrDetach() const {
+  if (is_sock) {
+    return DetachSocket();
+  }
+
+  // NOTE: This might happen if the file was unlinked after being opened.
+  // It's a common pattern in the case of temporary files and the like but
+  // we should not allow such usage from the zygote.
+  const int new_fd = TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags));
+
+  if (new_fd == -1) {
+    ALOGE("Failed open(%s, %d) : %s", file_path.c_str(), open_flags, strerror(errno));
+    return false;
+  }
+
+  if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFD, fd_flags)) == -1) {
+    close(new_fd);
+    ALOGE("Failed fcntl(%d, F_SETFD, %x) : %s", new_fd, fd_flags, strerror(errno));
+    return false;
+  }
+
+  if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFL, fs_flags)) == -1) {
+    close(new_fd);
+    ALOGE("Failed fcntl(%d, F_SETFL, %x) : %s", new_fd, fs_flags, strerror(errno));
+    return false;
+  }
+
+  if (offset != -1 && TEMP_FAILURE_RETRY(lseek64(new_fd, offset, SEEK_SET)) == -1) {
+    close(new_fd);
+    ALOGE("Failed lseek64(%d, SEEK_SET) : %s", new_fd, strerror(errno));
+    return false;
+  }
+
+  if (TEMP_FAILURE_RETRY(dup2(new_fd, fd)) == -1) {
+    close(new_fd);
+    ALOGE("Failed dup2(%d, %d) : %s", fd, new_fd, strerror(errno));
+    return false;
+  }
+
+  close(new_fd);
+
+  return true;
+}
+
+FileDescriptorInfo::FileDescriptorInfo(int fd) :
+  fd(fd),
+  stat(),
+  open_flags(0),
+  fd_flags(0),
+  fs_flags(0),
+  offset(0),
+  is_sock(true) {
+}
+
+FileDescriptorInfo::FileDescriptorInfo(struct stat stat, const std::string& file_path,
+                                       int fd, int open_flags, int fd_flags, int fs_flags,
+                                       off_t offset) :
+  fd(fd),
+  stat(stat),
+  file_path(file_path),
+  open_flags(open_flags),
+  fd_flags(fd_flags),
+  fs_flags(fs_flags),
+  offset(offset),
+  is_sock(false) {
+}
+
+// TODO: Call android::base::Readlink instead of copying the code here.
+// static
+bool FileDescriptorInfo::Readlink(const int fd, std::string* result) {
+  char path[64];
+  snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
+
+  // Code copied from android::base::Readlink starts here :
+
+  // Annoyingly, the readlink system call returns EINVAL for a zero-sized buffer,
+  // and truncates to whatever size you do supply, so it can't be used to query.
+  // We could call lstat first, but that would introduce a race condition that
+  // we couldn't detect.
+  // ext2 and ext4 both have PAGE_SIZE limitations, so we assume that here.
+  char buf[4096];
+  ssize_t len = readlink(path, buf, sizeof(buf));
+  if (len == -1) return false;
+
+  result->assign(buf, len);
+  return true;
+}
+
+// static
+bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) {
+  sockaddr_storage ss;
+  sockaddr* addr = reinterpret_cast<sockaddr*>(&ss);
+  socklen_t addr_len = sizeof(ss);
+
+  if (TEMP_FAILURE_RETRY(getsockname(fd, addr, &addr_len)) == -1) {
+    ALOGE("Failed getsockname(%d) : %s", fd, strerror(errno));
+    return false;
+  }
+
+  if (addr->sa_family != AF_UNIX) {
+    ALOGE("Unsupported socket (fd=%d) with family %d", fd, addr->sa_family);
+    return false;
+  }
+
+  const sockaddr_un* unix_addr = reinterpret_cast<const sockaddr_un*>(&ss);
+
+  size_t path_len = addr_len - offsetof(struct sockaddr_un, sun_path);
+  // This is an unnamed local socket, we do not accept it.
+  if (path_len == 0) {
+    ALOGE("Unsupported AF_UNIX socket (fd=%d) with empty path.", fd);
+    return false;
+  }
+
+  // This is a local socket with an abstract address, we do not accept it.
+  if (unix_addr->sun_path[0] == '\0') {
+    ALOGE("Unsupported AF_UNIX socket (fd=%d) with abstract address.", fd);
+    return false;
+  }
+
+  // If we're here, sun_path must refer to a null terminated filesystem
+  // pathname (man 7 unix). Remove the terminator before assigning it to an
+  // std::string.
+  if (unix_addr->sun_path[path_len - 1] ==  '\0') {
+    --path_len;
+  }
+
+  result->assign(unix_addr->sun_path, path_len);
+  return true;
+}
+
+bool FileDescriptorInfo::DetachSocket() const {
+  const int dev_null_fd = open("/dev/null", O_RDWR);
+  if (dev_null_fd < 0) {
+    ALOGE("Failed to open /dev/null : %s", strerror(errno));
+    return false;
+  }
+
+  if (dup2(dev_null_fd, fd) == -1) {
+    ALOGE("Failed dup2 on socket descriptor %d : %s", fd, strerror(errno));
+    return false;
+  }
+
+  if (close(dev_null_fd) == -1) {
+    ALOGE("Failed close(%d) : %s", dev_null_fd, strerror(errno));
+    return false;
+  }
+
+  return true;
+}
+
+// static
+FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore) {
+  DIR* d = opendir(kFdPath);
+  if (d == NULL) {
+    ALOGE("Unable to open directory %s: %s", kFdPath, strerror(errno));
+    return NULL;
+  }
+  int dir_fd = dirfd(d);
+  dirent* e;
+
+  std::unordered_map<int, FileDescriptorInfo*> open_fd_map;
+  while ((e = readdir(d)) != NULL) {
+    const int fd = ParseFd(e, dir_fd);
+    if (fd == -1) {
+      continue;
+    }
+    if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
+      ALOGI("Ignoring open file descriptor %d", fd);
+      continue;
+    }
+
+    FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd);
+    if (info == NULL) {
+      if (closedir(d) == -1) {
+        ALOGE("Unable to close directory : %s", strerror(errno));
+      }
+      return NULL;
+    }
+    open_fd_map[fd] = info;
+  }
+
+  if (closedir(d) == -1) {
+    ALOGE("Unable to close directory : %s", strerror(errno));
+    return NULL;
+  }
+  return new FileDescriptorTable(open_fd_map);
+}
+
+bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore) {
+  std::set<int> open_fds;
+
+  // First get the list of open descriptors.
+  DIR* d = opendir(kFdPath);
+  if (d == NULL) {
+    ALOGE("Unable to open directory %s: %s", kFdPath, strerror(errno));
+    return false;
+  }
+
+  int dir_fd = dirfd(d);
+  dirent* e;
+  while ((e = readdir(d)) != NULL) {
+    const int fd = ParseFd(e, dir_fd);
+    if (fd == -1) {
+      continue;
+    }
+    if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
+      ALOGI("Ignoring open file descriptor %d", fd);
+      continue;
+    }
+
+    open_fds.insert(fd);
+  }
+
+  if (closedir(d) == -1) {
+    ALOGE("Unable to close directory : %s", strerror(errno));
+    return false;
+  }
+
+  return RestatInternal(open_fds);
+}
+
+// Reopens all file descriptors that are contained in the table. Returns true
+// if all descriptors were successfully re-opened or detached, and false if an
+// error occurred.
+bool FileDescriptorTable::ReopenOrDetach() {
+  std::unordered_map<int, FileDescriptorInfo*>::const_iterator it;
+  for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) {
+    const FileDescriptorInfo* info = it->second;
+    if (info == NULL || !info->ReopenOrDetach()) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+FileDescriptorTable::FileDescriptorTable(
+    const std::unordered_map<int, FileDescriptorInfo*>& map)
+    : open_fd_map_(map) {
+}
+
+bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds) {
+  bool error = false;
+
+  // Iterate through the list of file descriptors we've already recorded
+  // and check whether :
+  //
+  // (a) they continue to be open.
+  // (b) they refer to the same file.
+  std::unordered_map<int, FileDescriptorInfo*>::iterator it = open_fd_map_.begin();
+  while (it != open_fd_map_.end()) {
+    std::set<int>::const_iterator element = open_fds.find(it->first);
+    if (element == open_fds.end()) {
+      // The entry from the file descriptor table is no longer in the list
+      // of open files. We warn about this condition and remove it from
+      // the list of FDs under consideration.
+      //
+      // TODO(narayan): This will be an error in a future android release.
+      // error = true;
+      // ALOGW("Zygote closed file descriptor %d.", it->first);
+      it = open_fd_map_.erase(it);
+    } else {
+      // The entry from the file descriptor table is still open. Restat
+      // it and check whether it refers to the same file.
+      const bool same_file = it->second->Restat();
+      if (!same_file) {
+        // The file descriptor refers to a different description. We must
+        // update our entry in the table.
+        delete it->second;
+        it->second = FileDescriptorInfo::CreateFromFd(*element);
+        if (it->second == NULL) {
+          // The descriptor no longer no longer refers to a whitelisted file.
+          // We flag an error and remove it from the list of files we're
+          // tracking.
+          error = true;
+          it = open_fd_map_.erase(it);
+        } else {
+          // Successfully restatted the file, move on to the next open FD.
+          ++it;
+        }
+      } else {
+        // It's the same file. Nothing to do here. Move on to the next open
+        // FD.
+        ++it;
+      }
+
+      // Finally, remove the FD from the set of open_fds. We do this last because
+      // |element| will not remain valid after a call to erase.
+      open_fds.erase(element);
+    }
+  }
+
+  if (open_fds.size() > 0) {
+    // The zygote has opened new file descriptors since our last inspection.
+    // We warn about this condition and add them to our table.
+    //
+    // TODO(narayan): This will be an error in a future android release.
+    // error = true;
+    // ALOGW("Zygote opened %zd new file descriptor(s).", open_fds.size());
+
+    // TODO(narayan): This code will be removed in a future android release.
+    std::set<int>::const_iterator it;
+    for (it = open_fds.begin(); it != open_fds.end(); ++it) {
+      const int fd = (*it);
+      FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd);
+      if (info == NULL) {
+        // A newly opened file is not on the whitelist. Flag an error and
+        // continue.
+        error = true;
+      } else {
+        // Track the newly opened file.
+        open_fd_map_[fd] = info;
+      }
+    }
+  }
+
+  return !error;
+}
+
+// static
+int FileDescriptorTable::ParseFd(dirent* e, int dir_fd) {
+  char* end;
+  const int fd = strtol(e->d_name, &end, 10);
+  if ((*end) != '\0') {
+    return -1;
+  }
+
+  // Don't bother with the standard input/output/error, they're handled
+  // specially post-fork anyway.
+  if (fd <= STDERR_FILENO || fd == dir_fd) {
+    return -1;
+  }
+
+  return fd;
+}
diff --git a/core/jni/fd_utils.h b/core/jni/fd_utils.h
new file mode 100644
index 0000000..03298c3
--- /dev/null
+++ b/core/jni/fd_utils.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORKS_BASE_CORE_JNI_FD_UTILS_H_
+#define FRAMEWORKS_BASE_CORE_JNI_FD_UTILS_H_
+
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <dirent.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+
+#include <android-base/macros.h>
+
+// Whitelist of open paths that the zygote is allowed to keep open.
+//
+// In addition to the paths listed in kPathWhitelist in file_utils.cpp, and
+// paths dynamically added with Allow(), all files ending with ".jar"
+// under /system/framework" are whitelisted. See IsAllowed() for the canonical
+// definition.
+//
+// If the whitelisted path is associated with a regular file or a
+// character device, the file is reopened after a fork with the same
+// offset and mode. If the whilelisted  path is associated with a
+// AF_UNIX socket, the socket will refer to /dev/null after each
+// fork, and all operations on it will fail.
+class FileDescriptorWhitelist {
+ public:
+  // Lazily creates the global whitelist.
+  static FileDescriptorWhitelist* Get();
+
+  // Adds a path to the whitelist.
+  void Allow(const std::string& path) {
+    whitelist_.push_back(path);
+  }
+
+  // Returns true iff. a given path is whitelisted. A path is whitelisted
+  // if it belongs to the whitelist (see kPathWhitelist) or if it's a path
+  // under /system/framework that ends with ".jar" or if it is a system
+  // framework overlay.
+  bool IsAllowed(const std::string& path) const;
+
+ private:
+  FileDescriptorWhitelist();
+
+  static bool StartsWith(const std::string& str, const std::string& prefix);
+
+  static bool EndsWith(const std::string& str, const std::string& suffix);
+
+  static FileDescriptorWhitelist* instance_;
+
+  std::vector<std::string> whitelist_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileDescriptorWhitelist);
+};
+
+// Keeps track of all relevant information (flags, offset etc.) of an
+// open zygote file descriptor.
+class FileDescriptorInfo {
+ public:
+  // Create a FileDescriptorInfo for a given file descriptor. Returns
+  // |NULL| if an error occurred.
+  static FileDescriptorInfo* CreateFromFd(int fd);
+
+  // Checks whether the file descriptor associated with this object
+  // refers to the same description.
+  bool Restat() const;
+
+  bool ReopenOrDetach() const;
+
+  const int fd;
+  const struct stat stat;
+  const std::string file_path;
+  const int open_flags;
+  const int fd_flags;
+  const int fs_flags;
+  const off_t offset;
+  const bool is_sock;
+
+ private:
+  FileDescriptorInfo(int fd);
+
+  FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
+                     int fd_flags, int fs_flags, off_t offset);
+
+  static bool Readlink(const int fd, std::string* result);
+
+  // Returns the locally-bound name of the socket |fd|. Returns true
+  // iff. all of the following hold :
+  //
+  // - the socket's sa_family is AF_UNIX.
+  // - the length of the path is greater than zero (i.e, not an unnamed socket).
+  // - the first byte of the path isn't zero (i.e, not a socket with an abstract
+  //   address).
+  static bool GetSocketName(const int fd, std::string* result);
+
+  bool DetachSocket() const;
+
+  DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo);
+};
+
+// A FileDescriptorTable is a collection of FileDescriptorInfo objects
+// keyed by their FDs.
+class FileDescriptorTable {
+ public:
+  // Creates a new FileDescriptorTable. This function scans
+  // /proc/self/fd for the list of open file descriptors and collects
+  // information about them. Returns NULL if an error occurs.
+  static FileDescriptorTable* Create(const std::vector<int>& fds_to_ignore);
+
+  bool Restat(const std::vector<int>& fds_to_ignore);
+
+  // Reopens all file descriptors that are contained in the table. Returns true
+  // if all descriptors were successfully re-opened or detached, and false if an
+  // error occurred.
+  bool ReopenOrDetach();
+
+ private:
+  FileDescriptorTable(const std::unordered_map<int, FileDescriptorInfo*>& map);
+
+  bool RestatInternal(std::set<int>& open_fds);
+
+  static int ParseFd(dirent* e, int dir_fd);
+
+  // Invariant: All values in this unordered_map are non-NULL.
+  std::unordered_map<int, FileDescriptorInfo*> open_fd_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileDescriptorTable);
+};
+
+#endif  // FRAMEWORKS_BASE_CORE_JNI_FD_UTILS_H_
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 60cf810..048214a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -167,6 +167,8 @@
     <protected-broadcast
         android:name="android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED" />
     <protected-broadcast
+        android:name="android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED" />
+    <protected-broadcast
         android:name="android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast
         android:name="android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED" />
@@ -1230,6 +1232,12 @@
     <permission android:name="android.permission.SCORE_NETWORKS"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows applications to request network
+         recommendations and scores from the NetworkScoreService.
+         <p>Not for use by third-party applications. @hide -->
+    <permission android:name="android.permission.REQUEST_NETWORK_SCORES"
+        android:protectionLevel="signature" />
+
     <!-- ======================================= -->
     <!-- Permissions for short range, peripheral networks -->
     <!-- ======================================= -->
@@ -2046,6 +2054,12 @@
     <permission android:name="android.permission.RESET_SHORTCUT_MANAGER_THROTTLING"
         android:protectionLevel="signature" />
 
+    <!-- Allows the system to bind to the discovered Network Recommendation Service.
+         @SystemApi @hide -->
+    <permission android:name="android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE"
+        android:protectionLevel="signature" />
+    <uses-permission android:name="android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE"/>
+
     <!-- ========================================= -->
     <!-- Permissions for special development tools -->
     <!-- ========================================= -->
@@ -2634,7 +2648,10 @@
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to broadcast privileged networking requests.
-         <p>Not for use by third-party applications. @hide -->
+         <p>Not for use by third-party applications.
+         @hide
+         @deprecated Use {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} instead
+    -->
     <permission android:name="android.permission.BROADCAST_NETWORK_PRIVILEGED"
         android:protectionLevel="signature|privileged" />
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4cf1226..dbc4324 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1280,9 +1280,8 @@
     <!-- A list of potential packages, in priority order, that may contain a
          network recommendation provider. A network recommendation provider must:
              * Be granted the SCORE_NETWORKS permission.
-             * Include a Receiver for the android.net.scoring.SCORE_NETWORKS action guarded by the
-               BROADCAST_NETWORK_PRIVILEGED permission.
-             * Include a Service for the android.net.scoring.RECOMMEND_NETWORKS action.
+             * Include a Service for the android.net.scoring.RECOMMEND_NETWORKS action
+               protected by the BIND_NETWORK_RECOMMENDATION_SERVICE permission.
 
          This may be empty if network scoring and recommending isn't supported.
          -->
@@ -2676,4 +2675,7 @@
 
     <!-- An array of packages for which notifications cannot be blocked. -->
     <string-array translatable="false" name="config_nonBlockableNotificationPackages" />
+
+    <!-- Component name of the default cell broadcast receiver -->
+    <string name="config_defaultCellBroadcastReceiverComponent" translatable="false">com.android.cellbroadcastreceiver/.PrivilegedCellBroadcastReceiver</string>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 5d399c1..38137f8 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2912,17 +2912,6 @@
     <!-- If there is ever a ringtone set for some setting, but that ringtone can no longer be resolved, t his is shown instead.  For example, if the ringtone was on a SD card and it had been removed, this woudl be shown for ringtones on that SD card. -->
     <string name="ringtone_unknown">Unknown ringtone</string>
 
-    <!-- A notification is shown when there are open wireless networks nearby.  This is the notification's title. -->
-    <plurals name="wifi_available">
-        <item quantity="one">Wi-Fi network available</item>
-        <item quantity="other">Wi-Fi networks available</item>
-    </plurals>
-    <!-- A notification is shown when there are open wireless networks nearby.  This is the notification's message. -->
-    <plurals name="wifi_available_detailed">
-        <item quantity="one">Open Wi-Fi network available</item>
-        <item quantity="other">Open Wi-Fi networks available</item>
-    </plurals>
-
     <!-- A notification is shown when a wifi captive portal network is detected.  This is the notification's title. -->
     <string name="wifi_available_sign_in">Sign in to Wi-Fi network</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index fe88cd1..9db131b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1787,8 +1787,6 @@
   <java-symbol type="layout" name="safe_mode" />
   <java-symbol type="layout" name="simple_list_item_2_single_choice" />
   <java-symbol type="layout" name="app_error_dialog" />
-  <java-symbol type="plurals" name="wifi_available" />
-  <java-symbol type="plurals" name="wifi_available_detailed" />
   <java-symbol type="string" name="accessibility_binding_label" />
   <java-symbol type="string" name="adb_active_notification_message" />
   <java-symbol type="string" name="adb_active_notification_title" />
@@ -2739,4 +2737,6 @@
 
 <!-- Network Recommendation -->
   <java-symbol type="array" name="config_networkRecommendationPackageNames" />
+
+  <java-symbol type="string" name="config_defaultCellBroadcastReceiverComponent" />
 </resources>
diff --git a/core/tests/coretests/src/android/net/IpPrefixTest.java b/core/tests/coretests/src/android/net/IpPrefixTest.java
index fcc6389..4f2387d 100644
--- a/core/tests/coretests/src/android/net/IpPrefixTest.java
+++ b/core/tests/coretests/src/android/net/IpPrefixTest.java
@@ -18,14 +18,14 @@
 
 import android.net.IpPrefix;
 import android.os.Parcel;
-import static android.test.MoreAsserts.assertNotEqual;
 import android.test.suitebuilder.annotation.SmallTest;
-
-import static org.junit.Assert.assertArrayEquals;
 import java.net.InetAddress;
 import java.util.Random;
 import junit.framework.TestCase;
 
+import static android.test.MoreAsserts.assertNotEqual;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
 
 public class IpPrefixTest extends TestCase {
 
@@ -242,25 +242,42 @@
 
     @SmallTest
     public void testHashCode() {
-        IpPrefix p;
-        int oldCode = -1;
+        IpPrefix p = new IpPrefix(new byte[4], 0);
         Random random = new Random();
         for (int i = 0; i < 100; i++) {
+            final IpPrefix oldP = p;
             if (random.nextBoolean()) {
                 // IPv4.
                 byte[] b = new byte[4];
                 random.nextBytes(b);
                 p = new IpPrefix(b, random.nextInt(33));
-                assertNotEqual(oldCode, p.hashCode());
-                oldCode = p.hashCode();
             } else {
                 // IPv6.
                 byte[] b = new byte[16];
                 random.nextBytes(b);
                 p = new IpPrefix(b, random.nextInt(129));
-                assertNotEqual(oldCode, p.hashCode());
-                oldCode = p.hashCode();
             }
+            if (p.equals(oldP)) {
+              assertEquals(p.hashCode(), oldP.hashCode());
+            }
+            if (p.hashCode() != oldP.hashCode()) {
+              assertNotEqual(p, oldP);
+            }
+        }
+    }
+
+    @SmallTest
+    public void testHashCodeIsNotConstant() {
+        IpPrefix[] prefixes = {
+            new IpPrefix("2001:db8:f00::ace:d00d/127"),
+            new IpPrefix("192.0.2.0/23"),
+            new IpPrefix("::/0"),
+            new IpPrefix("0.0.0.0/0"),
+        };
+        for (int i = 0; i < prefixes.length; i++) {
+          for (int j = i + 1; j < prefixes.length; j++) {
+            assertNotEqual(prefixes[i].hashCode(), prefixes[j].hashCode());
+          }
         }
     }
 
diff --git a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
index 5bfff26..29020ba 100644
--- a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
+++ b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
@@ -169,6 +169,25 @@
         assertNull(activeScorer);
     }
 
+    public void testIsCallerActiveScorer_providerNotAvailable() throws Exception {
+        ContentResolver cr = mTargetContext.getContentResolver();
+        Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
+
+        assertFalse(mNetworkScorerAppManager.isCallerActiveScorer(924));
+    }
+
+    public void testIsCallerActiveScorer_providerAvailable() throws Exception {
+        setNetworkRecommendationPackageNames("package1");
+        mockScoreNetworksGranted("package1");
+        mockRecommendationServiceAvailable("package1", 924 /* packageUid */);
+
+        ContentResolver cr = mTargetContext.getContentResolver();
+        Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
+
+        assertTrue(mNetworkScorerAppManager.isCallerActiveScorer(924));
+        assertFalse(mNetworkScorerAppManager.isCallerActiveScorer(925));
+    }
+
     private void setNetworkRecommendationPackageNames(String... names) {
         if (names == null) {
             names = new String[0];
diff --git a/core/tests/coretests/src/android/net/ScoredNetworkTest.java b/core/tests/coretests/src/android/net/ScoredNetworkTest.java
index 9c3346e..e818c56 100644
--- a/core/tests/coretests/src/android/net/ScoredNetworkTest.java
+++ b/core/tests/coretests/src/android/net/ScoredNetworkTest.java
@@ -166,4 +166,52 @@
         assertTrue(newNetwork.meteredHint);
         assertNull(newNetwork.attributes);
     }
+
+    @Test
+    public void calculateBadgeShouldReturnNoBadgeWhenNoAttributesBundle() {
+        ScoredNetwork network = new ScoredNetwork(KEY, CURVE);
+        assertEquals(ScoredNetwork.BADGING_NONE, network.calculateBadge(TEST_RSSI));
+    }
+
+    @Test
+    public void calculateBadgeShouldReturnNoBadgeWhenNoBadgingCurveInBundle() {
+        ScoredNetwork network = new ScoredNetwork(KEY, CURVE, false /* meteredHint */, ATTRIBUTES);
+        assertEquals(ScoredNetwork.BADGING_NONE, network.calculateBadge(TEST_RSSI));
+    }
+
+    @Test
+    public void calculateBadgeShouldReturn4kBadge() {
+        ScoredNetwork network =
+            buildScoredNetworkWithGivenBadgeForTestRssi(ScoredNetwork.BADGING_4K);
+        assertEquals(ScoredNetwork.BADGING_4K, network.calculateBadge(TEST_RSSI));
+    }
+
+    @Test
+    public void calculateBadgeShouldReturnHdBadge() {
+        ScoredNetwork network =
+            buildScoredNetworkWithGivenBadgeForTestRssi(ScoredNetwork.BADGING_HD);
+        assertEquals(ScoredNetwork.BADGING_HD, network.calculateBadge(TEST_RSSI));
+    }
+
+    @Test
+    public void calculateBadgeShouldReturnSdBadge() {
+        ScoredNetwork network =
+            buildScoredNetworkWithGivenBadgeForTestRssi(ScoredNetwork.BADGING_SD);
+        assertEquals(ScoredNetwork.BADGING_SD, network.calculateBadge(TEST_RSSI));
+    }
+
+    @Test
+    public void calculateBadgeShouldReturnNoBadge() {
+        ScoredNetwork network =
+            buildScoredNetworkWithGivenBadgeForTestRssi(ScoredNetwork.BADGING_NONE);
+        assertEquals(ScoredNetwork.BADGING_NONE, network.calculateBadge(TEST_RSSI));
+    }
+
+    private ScoredNetwork buildScoredNetworkWithGivenBadgeForTestRssi(int badge) {
+        RssiCurve badgingCurve =
+               new RssiCurve(RSSI_START, 10, new byte[] {0, 0, 0, 0, 0, 0, (byte) badge});
+        Bundle attr = new Bundle();
+        attr.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, badgingCurve);
+        return new ScoredNetwork(KEY, CURVE, false /* meteredHint */, attr);
+    }
 }
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
index 9b2b9f1..836ede6 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
@@ -23,7 +23,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 8
 
 LOCAL_PACKAGE_NAME := MultiDexLegacyAndException
 
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
index 874263f..2915914 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
@@ -23,7 +23,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 8
 
 LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp
 
@@ -45,7 +45,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 8
 
 LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp2
 
diff --git a/docs/html/google/play/billing/billing_integrate.jd b/docs/html/google/play/billing/billing_integrate.jd
index 5d6b3a8..1f1939c 100755
--- a/docs/html/google/play/billing/billing_integrate.jd
+++ b/docs/html/google/play/billing/billing_integrate.jd
@@ -294,7 +294,7 @@
 skuList.add("premiumUpgrade");
 skuList.add("gas");
 Bundle querySkus = new Bundle();
-querySkus.putStringArrayList(“ITEM_ID_LIST”, skuList);
+querySkus.putStringArrayList("ITEM_ID_LIST", skuList);
 </pre>
 
 <p>
diff --git a/libs/androidfw/BackupData.cpp b/libs/androidfw/BackupData.cpp
index ba4a4ff..76a430e 100644
--- a/libs/androidfw/BackupData.cpp
+++ b/libs/androidfw/BackupData.cpp
@@ -16,14 +16,13 @@
 
 #define LOG_TAG "backup_data"
 
-#include <androidfw/BackupHelpers.h>
-#include <utils/ByteOrder.h>
-
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 
-#include <cutils/log.h>
+#include <androidfw/BackupHelpers.h>
+#include <log/log.h>
+#include <utils/ByteOrder.h>
 
 namespace android {
 
diff --git a/libs/androidfw/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp
index 78e9d91..8bfe2b6 100644
--- a/libs/androidfw/BackupHelpers.cpp
+++ b/libs/androidfw/BackupHelpers.cpp
@@ -18,23 +18,22 @@
 
 #include <androidfw/BackupHelpers.h>
 
-#include <utils/KeyedVector.h>
-#include <utils/ByteOrder.h>
-#include <utils/String8.h>
-
 #include <errno.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <sys/stat.h>
-#include <sys/time.h>  // for utimes
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>  // for utimes
+#include <sys/uio.h>
 #include <unistd.h>
 #include <utime.h>
-#include <fcntl.h>
 #include <zlib.h>
 
-#include <cutils/log.h>
+#include <log/log.h>
+#include <utils/ByteOrder.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
 
 namespace android {
 
diff --git a/libs/androidfw/include/androidfw/CursorWindow.h b/libs/androidfw/include/androidfw/CursorWindow.h
index 8a2979a..f543565 100644
--- a/libs/androidfw/include/androidfw/CursorWindow.h
+++ b/libs/androidfw/include/androidfw/CursorWindow.h
@@ -17,11 +17,11 @@
 #ifndef _ANDROID__DATABASE_WINDOW_H
 #define _ANDROID__DATABASE_WINDOW_H
 
-#include <cutils/log.h>
 #include <stddef.h>
 #include <stdint.h>
 
 #include <binder/Parcel.h>
+#include <log/log.h>
 #include <utils/String8.h>
 
 #if LOG_NDEBUG
diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp
index 9d5860c..f5bb821 100644
--- a/libs/hwui/AnimatorManager.cpp
+++ b/libs/hwui/AnimatorManager.cpp
@@ -142,7 +142,7 @@
 }
 
 uint32_t AnimatorManager::animateCommon(TreeInfo& info) {
-    uint32_t dirtyMask;
+    uint32_t dirtyMask = 0;
     AnimateFunctor functor(info, mAnimationHandle->context(), &dirtyMask);
     auto newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
     mAnimators.erase(newEnd, mAnimators.end());
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index 6d5833b..2b4fe17 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -16,7 +16,7 @@
 
 #include "DamageAccumulator.h"
 
-#include <cutils/log.h>
+#include <log/log.h>
 
 #include "RenderNode.h"
 #include "utils/MathUtils.h"
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index 4cfbb2a..ff3ee22 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -13,16 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include <DeviceInfo.h>
 
 #include "Extensions.h"
 
-#include <GLES2/gl2.h>
-#include <log/log.h>
-
 #include <thread>
 #include <mutex>
 
+#include <log/log.h>
+
+#include <GLES2/gl2.h>
+
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/GpuMemoryTracker.h b/libs/hwui/GpuMemoryTracker.h
index bfb1bf1..352f3d7 100644
--- a/libs/hwui/GpuMemoryTracker.h
+++ b/libs/hwui/GpuMemoryTracker.h
@@ -15,10 +15,11 @@
  */
 #pragma once
 
-#include <cutils/log.h>
 #include <pthread.h>
 #include <ostream>
 
+#include <log/log.h>
+
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/Interpolator.cpp b/libs/hwui/Interpolator.cpp
index cc47f00..9af8eeb 100644
--- a/libs/hwui/Interpolator.cpp
+++ b/libs/hwui/Interpolator.cpp
@@ -16,10 +16,11 @@
 
 #include "Interpolator.h"
 
-#include "utils/MathUtils.h"
-
 #include <algorithm>
-#include <cutils/log.h>
+
+#include <log/log.h>
+
+#include "utils/MathUtils.h"
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index ed6b211..2132c2b 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -13,21 +13,24 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include "JankTracker.h"
 
+#include <errno.h>
+#include <inttypes.h>
+#include <sys/mman.h>
+
+#include <algorithm>
+#include <cmath>
+#include <cstdio>
+#include <limits>
+
+#include <cutils/ashmem.h>
+#include <log/log.h>
+
 #include "Properties.h"
 #include "utils/TimeUtils.h"
 
-#include <algorithm>
-#include <cutils/ashmem.h>
-#include <cutils/log.h>
-#include <cstdio>
-#include <errno.h>
-#include <inttypes.h>
-#include <limits>
-#include <cmath>
-#include <sys/mman.h>
-
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/PixelBuffer.h b/libs/hwui/PixelBuffer.h
index bbef36b..280af87 100644
--- a/libs/hwui/PixelBuffer.h
+++ b/libs/hwui/PixelBuffer.h
@@ -18,7 +18,8 @@
 #define ANDROID_HWUI_PIXEL_BUFFER_H
 
 #include <GLES3/gl3.h>
-#include <cutils/log.h>
+
+#include <log/log.h>
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 6f68c2b..c1e2e5e 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -13,17 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include "Properties.h"
-
 #include "Debug.h"
 
-#include <cutils/compiler.h>
-#include <cutils/log.h>
-#include <cutils/properties.h>
-
 #include <algorithm>
 #include <cstdlib>
 
+#include <cutils/compiler.h>
+#include <cutils/properties.h>
+#include <log/log.h>
+
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index 9df32b28..5db5efb 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -16,7 +16,10 @@
 
 #include "SkiaCanvasProxy.h"
 
-#include <cutils/log.h>
+#include <memory>
+
+#include <log/log.h>
+
 #include <SkPatchUtils.h>
 #include <SkPaint.h>
 #include <SkPath.h>
@@ -24,8 +27,6 @@
 #include <SkRect.h>
 #include <SkRRect.h>
 
-#include <memory>
-
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index a455f57..159a144 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -16,9 +16,10 @@
 
 #include "MinikinSkia.h"
 
+#include <log/log.h>
+
 #include <SkPaint.h>
 #include <SkTypeface.h>
-#include <cutils/log.h>
 
 namespace android {
 
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
index 67b775d..eda94bf 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -13,15 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include "MinikinUtils.h"
 
+#include <string>
+
+#include <log/log.h>
+
 #include "Paint.h"
 #include "SkPathMeasure.h"
 #include "Typeface.h"
 
-#include <cutils/log.h>
-#include <string>
-
 namespace android {
 
 FontStyle MinikinUtils::prepareMinikinPaint(MinikinPaint* minikinPaint, FontCollection** pFont,
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index ac6a28f..99bc9a7 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -16,16 +16,18 @@
 
 #include "EglManager.h"
 
+#include <string>
+
+#include "utils/StringUtils.h"
+#include <cutils/properties.h>
+#include <log/log.h>
+
 #include "Caches.h"
 #include "DeviceInfo.h"
 #include "Properties.h"
 #include "RenderThread.h"
 #include "renderstate/RenderState.h"
-#include "utils/StringUtils.h"
-#include <cutils/log.h>
-#include <cutils/properties.h>
 #include <EGL/eglext.h>
-#include <string>
 
 #define GLES_VERSION 2
 
@@ -134,7 +136,12 @@
 void EglManager::initExtensions() {
     auto extensions = StringUtils::split(
             eglQueryString(mEglDisplay, EGL_EXTENSIONS));
-    EglExtensions.bufferAge = extensions.has("EGL_EXT_buffer_age");
+    // For our purposes we don't care if EGL_BUFFER_AGE is a result of
+    // EGL_EXT_buffer_age or EGL_KHR_partial_update as our usage is covered
+    // under EGL_KHR_partial_update and we don't need the expanded scope
+    // that EGL_EXT_buffer_age provides.
+    EglExtensions.bufferAge = extensions.has("EGL_EXT_buffer_age")
+            || extensions.has("EGL_KHR_partial_update");
     EglExtensions.setDamage = extensions.has("EGL_KHR_partial_update");
     LOG_ALWAYS_FATAL_IF(!extensions.has("EGL_KHR_swap_buffers_with_damage"),
             "Missing required extension EGL_KHR_swap_buffers_with_damage");
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index c5af061..6533c2e 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -22,8 +22,8 @@
 #include "renderthread/RenderProxy.h"
 #include "renderthread/RenderTask.h"
 
-#include <cutils/log.h>
 #include <gui/Surface.h>
+#include <log/log.h>
 #include <ui/PixelFormat.h>
 
 using namespace android;
diff --git a/libs/hwui/utils/GLUtils.h b/libs/hwui/utils/GLUtils.h
index b49c1eb..f8dfe10 100644
--- a/libs/hwui/utils/GLUtils.h
+++ b/libs/hwui/utils/GLUtils.h
@@ -18,7 +18,7 @@
 
 #include "Debug.h"
 
-#include <cutils/log.h>
+#include <log/log.h>
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index abef66f..07bcbd3 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -15,7 +15,6 @@
  */
 
 #define LOG_TAG "PointerController"
-
 //#define LOG_NDEBUG 0
 
 // Log debug messages about pointer updates
@@ -23,8 +22,9 @@
 
 #include "PointerController.h"
 
-#include <cutils/log.h>
+#include <log/log.h>
 
+// ToDo: Fix code to be warning free
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 #include <SkBitmap.h>
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index 0bc832a..049b76e 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -15,15 +15,15 @@
  */
 
 #define LOG_TAG "Sprites"
-
 //#define LOG_NDEBUG 0
 
 #include "SpriteController.h"
 
-#include <cutils/log.h>
+#include <log/log.h>
 #include <utils/String8.h>
 #include <gui/Surface.h>
 
+// ToDo: Fix code to be warning free
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 #include <SkBitmap.h>
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 33c1c3f..ce75bb49 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3278,6 +3278,20 @@
         return delay;
     }
 
+     /**
+     * Indicate A2DP device configuration has changed.
+     * @param device Bluetooth device whose configuration has changed.
+     * {@hide}
+     */
+    public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device) {
+        IAudioService service = getService();
+        try {
+            service.handleBluetoothA2dpDeviceConfigChange(device);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /** {@hide} */
     public IRingtonePlayer getRingtonePlayer() {
         try {
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index f597440..8a28255 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -678,6 +678,9 @@
     public static native int setDeviceConnectionState(int device, int state,
                                                       String device_address, String device_name);
     public static native int getDeviceConnectionState(int device, String device_address);
+    public static native int handleDeviceConfigChange(int device,
+                                                      String device_address,
+                                                      String device_name);
     public static native int setPhoneState(int state);
     public static native int setForceUse(int usage, int config);
     public static native int getForceUse(int usage);
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index c7931fc..9e5ac72 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -133,6 +133,8 @@
 
     int setBluetoothA2dpDeviceConnectionState(in BluetoothDevice device, int state, int profile);
 
+    void handleBluetoothA2dpDeviceConfigChange(in BluetoothDevice device);
+
     AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer);
 
     boolean isCameraSoundForced();
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 949acc0..d0f8b73b 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -2336,10 +2336,7 @@
     }
 
     private void scanInternalSubtitleTracks() {
-        if (mSubtitleController == null) {
-            Log.d(TAG, "setSubtitleAnchor in MediaPlayer");
-            setSubtitleAnchor();
-        }
+        setSubtitleAnchor();
 
         populateInbandTracks();
 
diff --git a/media/mca/filterpacks/native/base/geometry.cpp b/media/mca/filterpacks/native/base/geometry.cpp
index 7812d502..44b13e4 100644
--- a/media/mca/filterpacks/native/base/geometry.cpp
+++ b/media/mca/filterpacks/native/base/geometry.cpp
@@ -13,10 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define LOG_TAG "geometry"
 
-#include <cutils/log.h>
 #include <cmath>
 
+#include <log/log.h>
+
 #include "geometry.h"
 
 namespace android {
diff --git a/media/mca/filterpacks/native/base/time_util.cpp b/media/mca/filterpacks/native/base/time_util.cpp
index 1a78a95..7d383df 100644
--- a/media/mca/filterpacks/native/base/time_util.cpp
+++ b/media/mca/filterpacks/native/base/time_util.cpp
@@ -13,14 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define LOG_TAG "time_util"
 
 #include "time_util.h"
 #include "utilities.h"
 
-#include <cutils/log.h>
 #include <sys/time.h>
 #include <map>
 
+#include <log/log.h>
+
 namespace android {
 namespace filterfw {
 
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 33c9655..5843637 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -17,4 +17,5 @@
     name: "libandroid.ndk",
     symbol_file: "libandroid.map.txt",
     first_version: "9",
+    unversioned_until: "current",
 }
diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp
index e09b0b4..17feb53 100644
--- a/native/graphics/jni/Android.bp
+++ b/native/graphics/jni/Android.bp
@@ -17,4 +17,5 @@
     name: "libjnigraphics.ndk",
     symbol_file: "libjnigraphics.map.txt",
     first_version: "9",
+    unversioned_until: "current",
 }
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index bb8eb2c..23a8655 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -55,12 +55,15 @@
 import java.util.Random;
 
 public class CaptivePortalLoginActivity extends Activity {
-    private static final String TAG = "CaptivePortalLogin";
+    private static final String TAG = CaptivePortalLoginActivity.class.getSimpleName();
+    private static final boolean DBG = true;
+
     private static final int SOCKET_TIMEOUT_MS = 10000;
 
     private enum Result { DISMISSED, UNWANTED, WANTED_AS_IS };
 
-    private URL mURL;
+    private URL mUrl;
+    private String mUserAgent;
     private Network mNetwork;
     private CaptivePortal mCaptivePortal;
     private NetworkCallback mNetworkCallback;
@@ -72,17 +75,20 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mCm = ConnectivityManager.from(this);
-        String url = getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL);
-        if (url == null) url = mCm.getCaptivePortalServerUrl();
-        try {
-            mURL = new URL(url);
-        } catch (MalformedURLException e) {
-            // System misconfigured, bail out in a way that at least provides network access.
-            Log.e(TAG, "Invalid captive portal URL, url=" + url);
-            done(Result.WANTED_AS_IS);
-        }
         mNetwork = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_NETWORK);
         mCaptivePortal = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL);
+        mUserAgent = getIntent().getParcelableExtra(
+                ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT);
+        mUrl = getUrl();
+        if (mUrl == null) {
+            // getUrl() failed to parse the url provided in the intent: bail out in a way that
+            // at least provides network access.
+            done(Result.WANTED_AS_IS);
+            return;
+        }
+        if (DBG) {
+            Log.d(TAG, String.format("onCreate for %s", mUrl.toString()));
+        }
 
         // Also initializes proxy system properties.
         mCm.bindProcessToNetwork(mNetwork);
@@ -149,6 +155,9 @@
     }
 
     private void done(Result result) {
+        if (DBG) {
+            Log.d(TAG, String.format("Result %s for %s", result.name(), mUrl.toString()));
+        }
         if (mNetworkCallback != null) {
             mCm.unregisterNetworkCallback(mNetworkCallback);
             mNetworkCallback = null;
@@ -185,22 +194,31 @@
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-        int id = item.getItemId();
-        if (id == R.id.action_use_network) {
-            done(Result.WANTED_AS_IS);
-            return true;
+        final Result result;
+        final String action;
+        final int id = item.getItemId();
+        switch (id) {
+            case R.id.action_use_network:
+                result = Result.WANTED_AS_IS;
+                action = "USE_NETWORK";
+                break;
+            case R.id.action_do_not_use_network:
+                result = Result.UNWANTED;
+                action = "DO_NOT_USE_NETWORK";
+                break;
+            default:
+                return super.onOptionsItemSelected(item);
         }
-        if (id == R.id.action_do_not_use_network) {
-            done(Result.UNWANTED);
-            return true;
+        if (DBG) {
+            Log.d(TAG, String.format("onOptionsItemSelect %s for %s", action, mUrl.toString()));
         }
-        return super.onOptionsItemSelected(item);
+        done(result);
+        return true;
     }
 
     @Override
     public void onDestroy() {
         super.onDestroy();
-
         if (mNetworkCallback != null) {
             mCm.unregisterNetworkCallback(mNetworkCallback);
             mNetworkCallback = null;
@@ -215,11 +233,29 @@
                 } catch (InterruptedException e) {
                 }
             }
-            startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(mURL.toString())));
+            final String url = mUrl.toString();
+            if (DBG) {
+                Log.d(TAG, "starting activity with intent ACTION_VIEW for " + url);
+            }
+            startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
         }
     }
 
+    private URL getUrl() {
+        String url = getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL);
+        if (url == null) {
+            url = mCm.getCaptivePortalServerUrl();
+        }
+        try {
+            return new URL(url);
+        } catch (MalformedURLException e) {
+            Log.e(TAG, "Invalid captive portal URL " + url);
+        }
+        return null;
+    }
+
     private void testForCaptivePortal() {
+        // TODO: reuse NetworkMonitor facilities for consistent captive portal detection.
         new Thread(new Runnable() {
             public void run() {
                 // Give time for captive portal to open.
@@ -230,11 +266,14 @@
                 HttpURLConnection urlConnection = null;
                 int httpResponseCode = 500;
                 try {
-                    urlConnection = (HttpURLConnection) mURL.openConnection();
+                    urlConnection = (HttpURLConnection) mNetwork.openConnection(mUrl);
                     urlConnection.setInstanceFollowRedirects(false);
                     urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
                     urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
                     urlConnection.setUseCaches(false);
+                    if (mUserAgent != null) {
+                       urlConnection.setRequestProperty("User-Agent", mUserAgent);
+                    }
                     urlConnection.getInputStream();
                     httpResponseCode = urlConnection.getResponseCode();
                 } catch (IOException e) {
@@ -292,7 +331,7 @@
                 // settings.  Now prompt the WebView read the Network-specific proxy settings.
                 setWebViewProxy();
                 // Load the real page.
-                view.loadUrl(mURL.toString());
+                view.loadUrl(mUrl.toString());
                 return;
             } else if (mPagesLoaded == 2) {
                 // Prevent going back to empty first page.
diff --git a/packages/CarrierDefaultApp/Android.mk b/packages/CarrierDefaultApp/Android.mk
new file mode 100644
index 0000000..82be132
--- /dev/null
+++ b/packages/CarrierDefaultApp/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CarrierDefaultApp
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
+# This finds and builds the test apk as well, so a single make does both.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/CarrierDefaultApp/AndroidManifest.xml b/packages/CarrierDefaultApp/AndroidManifest.xml
new file mode 100644
index 0000000..28d9e5c
--- /dev/null
+++ b/packages/CarrierDefaultApp/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.carrierdefaultapp"
+    android:sharedUserId="android.uid.phone" >
+
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+
+    <application android:label="@string/app_name" >
+        <receiver android:name="com.android.carrierdefaultapp.CarrierDefaultBroadcastReceiver">
+            <intent-filter>
+                <action android:name="android.intent.action.CARRIER_SIGNAL_REDIRECTED" />
+            </intent-filter>
+        </receiver>
+        <activity android:name="com.android.carrierdefaultapp.CaptivePortalLaunchActivity"
+            android:theme="@android:style/Theme.Translucent.NoTitleBar"
+            android:excludeFromRecents="true"/>
+    </application>
+</manifest>
diff --git a/packages/CarrierDefaultApp/res/drawable/ic_sim_card.xml b/packages/CarrierDefaultApp/res/drawable/ic_sim_card.xml
new file mode 100644
index 0000000..5896757
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/drawable/ic_sim_card.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Copyright (C) 2016 Google Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/glif_icon_size"
+    android:height="@dimen/glif_icon_size"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+    <path
+        android:fillColor="?android:attr/colorPrimary"
+        android:pathData="M39.98,8c0,-2.21 -1.77,-4 -3.98,-4L20,4L8,16v24c0,2.21 1.79,4 4,4h24.02c2.21,0 3.98,-1.79 3.98,-4l-0.02,-32zM18,38h-4v-4h4v4zM34,38h-4v-4h4v4zM18,30h-4v-8h4v8zM26,38h-4v-8h4v8zM26,26h-4v-4h4v4zM34,30h-4v-8h4v8z" />
+</vector>
\ No newline at end of file
diff --git a/packages/CarrierDefaultApp/res/values/dimens.xml b/packages/CarrierDefaultApp/res/values/dimens.xml
new file mode 100644
index 0000000..a3c5049
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values/dimens.xml
@@ -0,0 +1,3 @@
+<resources>
+    <dimen name="glif_icon_size">32dp</dimen>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values/strings.xml b/packages/CarrierDefaultApp/res/values/strings.xml
new file mode 100644
index 0000000..838ff39
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values/strings.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">CarrierDefaultApp</string>
+    <string name="portal_notification_id">Activate your service</string>
+    <string name="no_data_notification_id">No data service</string>
+    <string name="portal_notification_detail">Tap to activate your service</string>
+    <string name="no_data_notification_detail">No Service, please contact your service provider</string>
+    <string name="progress_dialogue_network_connection">Connecting to captive portal...</string>
+    <string name="alert_dialogue_network_timeout">Network timeout, would you like to retry?</string>
+    <string name="alert_dialogue_network_timeout_title">Network unavailable</string>
+    <string name="quit">Quit</string>
+    <string name="wait">Wait</string>
+</resources>
diff --git a/packages/CarrierDefaultApp/res/values/styles.xml b/packages/CarrierDefaultApp/res/values/styles.xml
new file mode 100644
index 0000000..3d26915
--- /dev/null
+++ b/packages/CarrierDefaultApp/res/values/styles.xml
@@ -0,0 +1,3 @@
+<resources>
+    <style name="AlertDialog" parent="android:Theme.Material.Light.Dialog.Alert"/>
+</resources>
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLaunchActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLaunchActivity.java
new file mode 100644
index 0000000..b7fde12
--- /dev/null
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLaunchActivity.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.carrierdefaultapp;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.CaptivePortal;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.NetworkRequest;
+import android.os.Bundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.Rlog;
+import android.telephony.SubscriptionManager;
+import android.text.TextUtils;
+import android.net.ICaptivePortal;
+import android.view.ContextThemeWrapper;
+import android.view.WindowManager;
+import com.android.carrierdefaultapp.R;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.util.ArrayUtils;
+
+import static android.net.CaptivePortal.APP_RETURN_DISMISSED;
+
+/**
+ * Activity that launches in response to the captive portal notification
+ * @see com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_SHOW_PORTAL_NOTIFICATION
+ * This activity requests network connection if there is no available one, launches the
+ * {@link com.android.captiveportallogin portalApp} and keeps track of the portal activation result.
+ */
+public class CaptivePortalLaunchActivity extends Activity {
+    private static final String TAG = CaptivePortalLaunchActivity.class.getSimpleName();
+    private static final boolean DBG = true;
+    public static final int NETWORK_REQUEST_TIMEOUT_IN_MS = 5 * 1000;
+
+    private ConnectivityManager mCm = null;
+    private ConnectivityManager.NetworkCallback mCb = null;
+    /* Progress dialogue when request network connection for captive portal */
+    private AlertDialog mProgressDialog = null;
+    /* Alert dialogue when network request is timeout */
+    private AlertDialog mAlertDialog = null;
+
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mCm = ConnectivityManager.from(this);
+        // Check network connection before loading portal
+        Network network = getNetworkForCaptivePortal();
+        NetworkInfo nwInfo = mCm.getNetworkInfo(network);
+        if (nwInfo == null || !nwInfo.isConnected()) {
+            if (DBG) logd("Network unavailable, request restricted connection");
+            requestNetwork(getIntent());
+        } else {
+            launchCaptivePortal(getIntent(), network);
+        }
+    }
+
+    // show progress dialog during network connecting
+    private void showConnectingProgressDialog() {
+        mProgressDialog = new ProgressDialog(getApplicationContext());
+        mProgressDialog.setMessage(getString(R.string.progress_dialogue_network_connection));
+        mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+        mProgressDialog.show();
+    }
+
+    // if network request is timeout, show alert dialog with two option: cancel & wait
+    private void showConnectionTimeoutAlertDialog() {
+        mAlertDialog = new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.AlertDialog))
+                .setMessage(getString(R.string.alert_dialogue_network_timeout))
+                .setTitle(getString(R.string.alert_dialogue_network_timeout_title))
+                .setNegativeButton(getString(R.string.quit),
+                        new DialogInterface.OnClickListener() {
+                            @Override
+                            public void onClick(DialogInterface dialog, int which) {
+                                // cancel
+                                dismissDialog(mAlertDialog);
+                                finish();
+                            }
+                        })
+                .setPositiveButton(getString(R.string.wait),
+                        new DialogInterface.OnClickListener() {
+                            @Override
+                            public void onClick(DialogInterface dialog, int which) {
+                                // wait, request network again
+                                dismissDialog(mAlertDialog);
+                                requestNetwork(getIntent());
+                            }
+                        })
+                .create();
+        mAlertDialog.show();
+    }
+
+    private void requestNetwork(final Intent intent) {
+        NetworkRequest request = new NetworkRequest.Builder()
+                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                .build();
+
+        mCb = new ConnectivityManager.NetworkCallback() {
+            @Override
+            public void onAvailable(Network network) {
+                if (DBG) logd("Network available: " + network);
+                dismissDialog(mProgressDialog);
+                mCm.bindProcessToNetwork(network);
+                launchCaptivePortal(intent, network);
+            }
+
+            @Override
+            public void onUnavailable() {
+                if (DBG) logd("Network unavailable");
+                dismissDialog(mProgressDialog);
+                showConnectionTimeoutAlertDialog();
+            }
+        };
+        showConnectingProgressDialog();
+        mCm.requestNetwork(request, mCb, NETWORK_REQUEST_TIMEOUT_IN_MS);
+    }
+
+    private void releaseNetworkRequest() {
+        logd("release Network Request");
+        if (mCb != null) {
+            mCm.unregisterNetworkCallback(mCb);
+            mCb = null;
+        }
+    }
+
+    private void dismissDialog(AlertDialog dialog) {
+        if (dialog != null) {
+            dialog.dismiss();
+        }
+    }
+
+    private Network getNetworkForCaptivePortal() {
+        Network[] info = mCm.getAllNetworks();
+        if (!ArrayUtils.isEmpty(info)) {
+            for (Network nw : info) {
+                final NetworkCapabilities nc = mCm.getNetworkCapabilities(nw);
+                if (nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
+                        && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
+                    return nw;
+                }
+            }
+        }
+        return null;
+    }
+
+    private void launchCaptivePortal(final Intent intent, Network network) {
+        String redirectUrl = intent.getStringExtra(TelephonyIntents.EXTRA_REDIRECTION_URL_KEY);
+        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+                SubscriptionManager.getDefaultVoiceSubscriptionId());
+        if (TextUtils.isEmpty(redirectUrl) || !matchUrl(redirectUrl, subId)) {
+            loge("Launch portal fails due to incorrect redirection URL: " +
+                    Rlog.pii(TAG, redirectUrl));
+            return;
+        }
+        final Intent portalIntent = new Intent(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN);
+        portalIntent.putExtra(ConnectivityManager.EXTRA_NETWORK, network);
+        portalIntent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL,
+                new CaptivePortal(new ICaptivePortal.Stub() {
+                    @Override
+                    public void appResponse(int response) {
+                        logd("portal response code: " + response);
+                        releaseNetworkRequest();
+                        if (response == APP_RETURN_DISMISSED) {
+                            // Upon success http response code, trigger re-evaluation
+                            CarrierActionUtils.applyCarrierAction(
+                                    CarrierActionUtils.CARRIER_ACTION_ENABLE_RADIO, intent,
+                                    getApplicationContext());
+                            CarrierActionUtils.applyCarrierAction(
+                                    CarrierActionUtils.CARRIER_ACTION_ENABLE_METERED_APNS, intent,
+                                    getApplicationContext());
+                            CarrierActionUtils.applyCarrierAction(
+                                    CarrierActionUtils.CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS,
+                                    intent, getApplicationContext());
+                        }
+                    }
+                }));
+        portalIntent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL, redirectUrl);
+        portalIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        if (DBG) logd("launching portal");
+        startActivity(portalIntent);
+        finish();
+    }
+
+    // match configured redirection url
+    private boolean matchUrl(String url, int subId) {
+        CarrierConfigManager configManager = getApplicationContext()
+                .getSystemService(CarrierConfigManager.class);
+        String[] redirectURLs = configManager.getConfigForSubId(subId).getStringArray(
+                CarrierConfigManager.KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY);
+        if (ArrayUtils.isEmpty(redirectURLs)) {
+            if (DBG) logd("match is unnecessary without any configured redirection url");
+            return true;
+        }
+        for (String redirectURL : redirectURLs) {
+            if (url.startsWith(redirectURL)) {
+                return true;
+            }
+        }
+        if (DBG) loge("no match found for configured redirection url");
+        return false;
+    }
+
+    private static void logd(String s) {
+        Rlog.d(TAG, s);
+    }
+
+    private static void loge(String s) {
+        Rlog.d(TAG, s);
+    }
+}
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
new file mode 100644
index 0000000..db4890f
--- /dev/null
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.carrierdefaultapp;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.carrierdefaultapp.R;
+/**
+ * This util class provides common logic for carrier actions
+ */
+public class CarrierActionUtils {
+    private static final String TAG = CarrierActionUtils.class.getSimpleName();
+
+    private static final String PORTAL_NOTIFICATION_TAG = "CarrierDefault.Portal.Notification";
+    private static final String NO_DATA_NOTIFICATION_TAG = "CarrierDefault.NoData.Notification";
+    private static final int PORTAL_NOTIFICATION_ID = 0;
+    private static final int NO_DATA_NOTIFICATION_ID = 1;
+    private static boolean ENABLE = true;
+
+    // A list of supported carrier action idx
+    public static final int CARRIER_ACTION_ENABLE_METERED_APNS               = 0;
+    public static final int CARRIER_ACTION_DISABLE_METERED_APNS              = 1;
+    public static final int CARRIER_ACTION_DISABLE_RADIO                     = 2;
+    public static final int CARRIER_ACTION_ENABLE_RADIO                      = 3;
+    public static final int CARRIER_ACTION_SHOW_PORTAL_NOTIFICATION          = 4;
+    public static final int CARRIER_ACTION_SHOW_NO_DATA_SERVICE_NOTIFICATION = 5;
+    public static final int CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS          = 6;
+
+    public static void applyCarrierAction(int actionIdx, Intent intent, Context context) {
+        switch (actionIdx) {
+            case CARRIER_ACTION_ENABLE_METERED_APNS:
+                onEnableAllMeteredApns(intent, context);
+                break;
+            case CARRIER_ACTION_DISABLE_METERED_APNS:
+                onDisableAllMeteredApns(intent, context);
+                break;
+            case CARRIER_ACTION_DISABLE_RADIO:
+                onDisableRadio(intent, context);
+                break;
+            case CARRIER_ACTION_ENABLE_RADIO:
+                onEnableRadio(intent, context);
+                break;
+            case CARRIER_ACTION_SHOW_PORTAL_NOTIFICATION:
+                onShowCaptivePortalNotification(intent, context);
+                break;
+            case CARRIER_ACTION_SHOW_NO_DATA_SERVICE_NOTIFICATION:
+                onShowNoDataServiceNotification(context);
+                break;
+            case CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS:
+                onCancelAllNotifications(context);
+                break;
+            default:
+                loge("unsupported carrier action index: " + actionIdx);
+        }
+    }
+
+    private static void onDisableAllMeteredApns(Intent intent, Context context) {
+        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+                SubscriptionManager.getDefaultVoiceSubscriptionId());
+        logd("onDisableAllMeteredApns subId: " + subId);
+        final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
+        telephonyMgr.carrierActionSetMeteredApnsEnabled(subId, !ENABLE);
+    }
+
+    private static void onEnableAllMeteredApns(Intent intent, Context context) {
+        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+                SubscriptionManager.getDefaultVoiceSubscriptionId());
+        logd("onEnableAllMeteredApns subId: " + subId);
+        final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
+        telephonyMgr.carrierActionSetMeteredApnsEnabled(subId, ENABLE);
+    }
+
+    private static void onDisableRadio(Intent intent, Context context) {
+        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+                SubscriptionManager.getDefaultVoiceSubscriptionId());
+        logd("onDisableRadio subId: " + subId);
+        final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
+        telephonyMgr.carrierActionSetRadioEnabled(subId, !ENABLE);
+    }
+
+    private static void onEnableRadio(Intent intent, Context context) {
+        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+                SubscriptionManager.getDefaultVoiceSubscriptionId());
+        logd("onEnableRadio subId: " + subId);
+        final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
+        telephonyMgr.carrierActionSetRadioEnabled(subId, ENABLE);
+    }
+
+    private static void onShowCaptivePortalNotification(Intent intent, Context context) {
+        logd("onShowCaptivePortalNotification");
+        final NotificationManager notificationMgr = context.getSystemService(
+                NotificationManager.class);
+        Intent portalIntent = new Intent(context, CaptivePortalLaunchActivity.class);
+        portalIntent.putExtras(intent);
+        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, portalIntent,
+                PendingIntent.FLAG_UPDATE_CURRENT);
+        Notification notification = getNotification(context, R.string.portal_notification_id,
+                R.string.portal_notification_detail, pendingIntent);
+        try {
+            notificationMgr.notify(PORTAL_NOTIFICATION_TAG, PORTAL_NOTIFICATION_ID, notification);
+        } catch (NullPointerException npe) {
+            loge("setNotificationVisible: " + npe);
+        }
+    }
+
+    private static void onShowNoDataServiceNotification(Context context) {
+        logd("onShowNoDataServiceNotification");
+        final NotificationManager notificationMgr = context.getSystemService(
+                NotificationManager.class);
+        Notification notification = getNotification(context, R.string.no_data_notification_id,
+                R.string.no_data_notification_detail, null);
+        try {
+            notificationMgr.notify(NO_DATA_NOTIFICATION_TAG, NO_DATA_NOTIFICATION_ID, notification);
+        } catch (NullPointerException npe) {
+            loge("setNotificationVisible: " + npe);
+        }
+    }
+
+    private static void onCancelAllNotifications(Context context) {
+        logd("onCancelAllNotifications");
+        final NotificationManager notificationMgr = context.getSystemService(
+                NotificationManager.class);
+        notificationMgr.cancelAll();
+    }
+
+    private static Notification getNotification(Context context, int titleId, int textId,
+                                         PendingIntent pendingIntent) {
+        Resources resources = context.getResources();
+        Notification.Builder builder = new Notification.Builder(context)
+                .setContentTitle(resources.getString(titleId))
+                .setContentText(resources.getString(textId))
+                .setSmallIcon(R.drawable.ic_sim_card)
+                .setOngoing(true)
+                .setPriority(Notification.PRIORITY_HIGH)
+                .setDefaults(Notification.DEFAULT_ALL)
+                .setVisibility(Notification.VISIBILITY_PUBLIC)
+                .setLocalOnly(true)
+                .setWhen(System.currentTimeMillis())
+                .setShowWhen(false);
+
+        if (pendingIntent != null) {
+            builder.setContentIntent(pendingIntent);
+        }
+        return builder.build();
+    }
+
+    private static void logd(String s) {
+        Log.d(TAG, s);
+    }
+
+    private static void loge(String s) {
+        Log.e(TAG, s);
+    }
+}
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierDefaultBroadcastReceiver.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierDefaultBroadcastReceiver.java
new file mode 100644
index 0000000..bc0fa02
--- /dev/null
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierDefaultBroadcastReceiver.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.carrierdefaultapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import java.util.List;
+
+public class CarrierDefaultBroadcastReceiver extends BroadcastReceiver{
+    private static final String TAG = CarrierDefaultBroadcastReceiver.class.getSimpleName();
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Log.d(TAG, "onReceive intent: " + intent.getAction());
+        List<Integer> actionList = CustomConfigLoader.loadCarrierActionList(context, intent);
+        for (int actionIdx : actionList) {
+            Log.d(TAG, "apply carrier action idx: " + actionIdx);
+            CarrierActionUtils.applyCarrierAction(actionIdx, intent, context);
+        }
+    }
+}
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java
new file mode 100644
index 0000000..e1125d9
--- /dev/null
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.carrierdefaultapp;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.Rlog;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.util.ArrayUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Default carrier app allows carrier customization. OEMs could configure a list
+ * of carrier actions defined in {@link com.android.carrierdefaultapp.CarrierActionUtils
+ * CarrierActionUtils} to act upon certain signal or even different args of the same signal.
+ * This allows different interpretations of the signal between carriers and could easily alter the
+ * app's behavior in a configurable way. This helper class loads and parses the carrier configs
+ * and return a list of predefined carrier actions for the given input signal.
+ */
+public class CustomConfigLoader {
+    // delimiters for parsing carrier configs of the form "arg1, arg2 : action1, action2"
+    private static final String INTRA_GROUP_DELIMITER = "\\s*,\\s*";
+    private static final String INTER_GROUP_DELIMITER = "\\s*:\\s*";
+
+    private static final String TAG = CustomConfigLoader.class.getSimpleName();
+    private static final boolean VDBG = Rlog.isLoggable(TAG, Log.VERBOSE);
+
+    /**
+     * loads and parses the carrier config, return a list of carrier action for the given signal
+     * @param context
+     * @param intent passing signal for config match
+     * @return a list of carrier action for the given signal based on the carrier config.
+     *
+     *  Example: input intent TelephonyIntent.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
+     *  This intent allows fined-grained matching based on both intent type & extra values:
+     *  apnType and errorCode.
+     *  apnType read from passing intent is "default" and errorCode is 0x26 for example and
+     *  returned carrier config from carrier_default_actions_on_redirection_string_array is
+     *  {
+     *      "default, 0x26:1,4", // 0x26(NETWORK_FAILURE)
+     *      "default, 0x70:2,3" // 0x70(APN_TYPE_CONFLICT)
+     *  }
+     *  [1, 4] // 1(CARRIER_ACTION_DISABLE_METERED_APNS), 4(CARRIER_ACTION_SHOW_PORTAL_NOTIFICATION)
+     *  returns as the action index list based on the matching rule.
+     */
+    public static List<Integer> loadCarrierActionList(Context context, Intent intent) {
+        CarrierConfigManager carrierConfigManager = (CarrierConfigManager) context.getSystemService(
+                Context.CARRIER_CONFIG_SERVICE);
+        // return an empty list if no match found
+        List<Integer> actionList = new ArrayList<>();
+        if (carrierConfigManager == null) {
+            Rlog.e(TAG, "load carrier config failure with carrier config manager uninitialized");
+            return actionList;
+        }
+        PersistableBundle b = carrierConfigManager.getConfig();
+        if (b != null) {
+            String[] configs = null;
+            // used for intents which allow fine-grained interpretation based on intent extras
+            String arg1 = null;
+            String arg2 = null;
+            switch (intent.getAction()) {
+                case TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED:
+                    configs = b.getStringArray(CarrierConfigManager
+                            .KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY);
+                    break;
+                case TelephonyIntents.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED:
+                    configs = b.getStringArray(CarrierConfigManager
+                            .KEY_CARRIER_DEFAULT_ACTIONS_ON_DCFAILURE_STRING_ARRAY);
+                    arg1 = intent.getStringExtra(TelephonyIntents.EXTRA_APN_TYPE_KEY);
+                    arg2 = intent.getStringExtra(TelephonyIntents.EXTRA_ERROR_CODE_KEY);
+                    break;
+                default:
+                    Rlog.e(TAG, "load carrier config failure with un-configured key: " +
+                            intent.getAction());
+                    break;
+            }
+            if (!ArrayUtils.isEmpty(configs)) {
+                for (String config : configs) {
+                    // parse each config until find the matching one
+                    matchConfig(config, arg1, arg2, actionList);
+                    if (!actionList.isEmpty()) {
+                        // return the first match
+                        if (VDBG) Rlog.d(TAG, "found match action list: " + actionList.toString());
+                        return actionList;
+                    }
+                }
+            }
+            Rlog.d(TAG, "no matching entry for signal: " + intent.getAction() + "arg1: " + arg1
+                    + "arg2: " + arg2);
+        }
+        return actionList;
+    }
+
+    /**
+     * Match based on the config's format and input args
+     * passing arg1, arg2 should match the format of the config
+     * case 1: config {actionIdx1, actionIdx2...} arg1 and arg2 must be null
+     * case 2: config {arg1, arg2 : actionIdx1, actionIdx2...} requires full match of non-null args
+     * case 3: config {arg1 : actionIdx1, actionIdx2...} only need to match arg1
+     *
+     * @param config action list config obtained from CarrierConfigManager
+     * @param arg1 first intent argument, set if required for config match
+     * @param arg2 second intent argument, set if required for config match
+     * @param actionList append each parsed action to the passing list
+     */
+    private static void matchConfig(String config, String arg1, String arg2,
+                                    List<Integer> actionList) {
+        String[] splitStr = config.trim().split(INTER_GROUP_DELIMITER, 2);
+        String actionStr = null;
+
+        if (splitStr.length == 1 && arg1 == null && arg2 == null) {
+            // case 1
+            actionStr = splitStr[0];
+        } else if (splitStr.length == 2 && arg1 != null && arg2 != null) {
+            // case 2
+            String[] args = splitStr[0].split(INTRA_GROUP_DELIMITER);
+            if (args.length == 2 && TextUtils.equals(arg1, args[0]) &&
+                    TextUtils.equals(arg2, args[1])) {
+                actionStr = splitStr[1];
+            }
+        } else if ((splitStr.length == 2) && (arg1 != null) && (arg2 == null)) {
+            // case 3
+            String[] args = splitStr[0].split(INTRA_GROUP_DELIMITER);
+            if (args.length == 1 && TextUtils.equals(arg1, args[0])) {
+                actionStr = splitStr[1];
+            }
+        }
+        // convert from string -> action idx list if found a matching entry
+        String[] actions = null;
+        if (!TextUtils.isEmpty(actionStr)) {
+            actions = actionStr.split(INTRA_GROUP_DELIMITER);
+        }
+        if (!ArrayUtils.isEmpty(actions)) {
+            for (String idx : actions) {
+                try {
+                    actionList.add(Integer.parseInt(idx));
+                } catch (NumberFormatException e) {
+                    Rlog.e(TAG, "NumberFormatException(string: " + idx + " config:" + config + "): "
+                            + e);
+                }
+            }
+        }
+    }
+}
diff --git a/packages/CarrierDefaultApp/tests/Android.mk b/packages/CarrierDefaultApp/tests/Android.mk
new file mode 100644
index 0000000..6ebb575
--- /dev/null
+++ b/packages/CarrierDefaultApp/tests/Android.mk
@@ -0,0 +1,25 @@
+# Copyright 2016, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_CERTIFICATE := platform
+
+# Include all makefiles in subdirectories
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
+
+
+
diff --git a/packages/CarrierDefaultApp/tests/unit/Android.mk b/packages/CarrierDefaultApp/tests/unit/Android.mk
new file mode 100644
index 0000000..092df50
--- /dev/null
+++ b/packages/CarrierDefaultApp/tests/unit/Android.mk
@@ -0,0 +1,34 @@
+# Copyright 2016, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+LOCAL_CERTIFICATE := platform
+
+LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test mockito-target-minus-junit4
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CarrierDefaultAppUnitTests
+
+LOCAL_INSTRUMENTATION_FOR := CarrierDefaultApp
+
+include $(BUILD_PACKAGE)
+
diff --git a/packages/CarrierDefaultApp/tests/unit/AndroidManifest.xml b/packages/CarrierDefaultApp/tests/unit/AndroidManifest.xml
new file mode 100644
index 0000000..3a06a09
--- /dev/null
+++ b/packages/CarrierDefaultApp/tests/unit/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.carrierdefaultapp.tests.unit">
+    <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.carrierdefaultapp"
+        android:label="CarrierDefaultApp Unit Test Cases">
+    </instrumentation>
+</manifest>
+
+
+
diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultActivityTestCase.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultActivityTestCase.java
new file mode 100644
index 0000000..c5a1243
--- /dev/null
+++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultActivityTestCase.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.carrierdefaultapp;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.test.ActivityUnitTestCase;
+import android.util.Log;
+
+import org.mockito.MockitoAnnotations;
+
+import java.util.HashMap;
+
+public class CarrierDefaultActivityTestCase<T extends Activity> extends ActivityUnitTestCase<T> {
+
+    protected TestContext mContext;
+
+    private T mActivity;
+
+    CarrierDefaultActivityTestCase(Class<T> activityClass) {
+        super(activityClass);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        MockitoAnnotations.initMocks(this);
+        mContext = new TestContext(getInstrumentation().getTargetContext());
+        setActivityContext(mContext);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    protected T startActivity() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity = startActivity(createActivityIntent(), null, null);
+            }
+        });
+        return mActivity;
+    }
+
+    protected void stopActivity() throws Exception {
+        getInstrumentation().callActivityOnStop(mActivity);
+    }
+
+    protected Intent createActivityIntent() {
+        Intent intent = new Intent();
+        return intent;
+    }
+
+    protected <S> void injectSystemService(Class<S> cls, S service) {
+        mContext.injectSystemService(cls, service);
+    }
+}
\ No newline at end of file
diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java
new file mode 100644
index 0000000..f9dbcd4
--- /dev/null
+++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.carrierdefaultapp;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.Rlog;
+import android.telephony.TelephonyManager;
+import android.test.InstrumentationTestCase;
+
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.TelephonyIntents;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+public class CarrierDefaultReceiverTest extends InstrumentationTestCase {
+    @Mock
+    private NotificationManager mNotificationMgr;
+    @Mock
+    private TelephonyManager mTelephonyMgr;
+    @Mock
+    private CarrierConfigManager mCarrierConfigMgr;
+    @Captor
+    private ArgumentCaptor<Integer> mInt;
+    @Captor
+    private ArgumentCaptor<Notification> mNotification;
+    @Captor
+    private ArgumentCaptor<String> mString;
+    private TestContext mContext;
+    private CarrierDefaultBroadcastReceiver mReceiver;
+    private static String TAG;
+
+    private static final String PORTAL_NOTIFICATION_TAG = "CarrierDefault.Portal.Notification";
+    private static final int PORTAL_NOTIFICATION_ID = 0;
+    private static int subId = 0;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        TAG = this.getClass().getSimpleName();
+        MockitoAnnotations.initMocks(this);
+        mContext = new TestContext(getInstrumentation().getTargetContext());
+        mContext.injectSystemService(NotificationManager.class, mNotificationMgr);
+        mContext.injectSystemService(TelephonyManager.class, mTelephonyMgr);
+        mContext.injectSystemService(CarrierConfigManager.class, mCarrierConfigMgr);
+
+        mReceiver = new CarrierDefaultBroadcastReceiver();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    @Test
+    public void testOnReceiveRedirection() {
+        // carrier action idx list includes 4(portal notification) & 1(disable metered APNs)
+        // upon redirection signal
+        PersistableBundle b = new PersistableBundle();
+        b.putStringArray(CarrierConfigManager
+                .KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY, new String[]{"4,1"});
+        doReturn(b).when(mCarrierConfigMgr).getConfig();
+
+        Intent intent = new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED);
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
+        Rlog.d(TAG, "OnReceive redirection intent");
+        mReceiver.onReceive(mContext, intent);
+
+        mContext.waitForMs(100);
+
+        Rlog.d(TAG, "verify carrier action: showPortalNotification");
+        verify(mNotificationMgr, times(1)).notify(mString.capture(), mInt.capture(),
+                mNotification.capture());
+        assertEquals(PORTAL_NOTIFICATION_ID, (int) mInt.getValue());
+        assertEquals(PORTAL_NOTIFICATION_TAG, mString.getValue());
+        PendingIntent pendingIntent = mNotification.getValue().contentIntent;
+        assertNotNull(pendingIntent);
+
+        Rlog.d(TAG, "verify carrier action: disable all metered apns");
+        verify(mTelephonyMgr).carrierActionSetMeteredApnsEnabled(eq(subId), eq(false));
+    }
+}
diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/LaunchCaptivePortalActivityTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/LaunchCaptivePortalActivityTest.java
new file mode 100644
index 0000000..8a18d72
--- /dev/null
+++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/LaunchCaptivePortalActivityTest.java
@@ -0,0 +1,108 @@
+package com.android.carrierdefaultapp;
+
+import android.annotation.TargetApi;
+import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.NetworkRequest;
+
+import com.android.internal.telephony.TelephonyIntents;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+public class LaunchCaptivePortalActivityTest extends
+        CarrierDefaultActivityTestCase<CaptivePortalLaunchActivity> {
+
+    @Mock
+    private ConnectivityManager mCm;
+    @Mock
+    private NetworkInfo mNetworkInfo;
+    @Mock
+    private Network mNetwork;
+
+    @Captor
+    private ArgumentCaptor<Integer> mInt;
+    @Captor
+    private ArgumentCaptor<NetworkRequest> mNetworkReq;
+
+    private NetworkCapabilities mNetworkCapabilities;
+
+    public LaunchCaptivePortalActivityTest() {
+        super(CaptivePortalLaunchActivity.class);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        injectSystemService(ConnectivityManager.class, mCm);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    @Override
+    protected Intent createActivityIntent() {
+        Intent intent = new Intent(getInstrumentation().getTargetContext(),
+                CaptivePortalLaunchActivity.class);
+        intent.putExtra(TelephonyIntents.EXTRA_REDIRECTION_URL_KEY, "url");
+        return intent;
+    }
+
+    @Test
+    public void testWithoutInternetConnection() throws Throwable {
+        startActivity();
+        TestContext.waitForMs(100);
+        verify(mCm, atLeast(1)).requestNetwork(mNetworkReq.capture(), any(), mInt.capture());
+        // verify network request
+        assert(mNetworkReq.getValue().networkCapabilities.hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_INTERNET));
+        assert(mNetworkReq.getValue().networkCapabilities.hasTransport(
+                NetworkCapabilities.TRANSPORT_CELLULAR));
+        assertFalse(mNetworkReq.getValue().networkCapabilities.hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED));
+        assertEquals(CaptivePortalLaunchActivity.NETWORK_REQUEST_TIMEOUT_IN_MS,
+                (int) mInt.getValue());
+        // verify captive portal app is not launched due to unavailable network
+        assertNull(getStartedActivityIntent());
+        stopActivity();
+    }
+
+    @Test
+    public void testWithInternetConnection() throws Throwable {
+        // Mock internet connection
+        mNetworkCapabilities = new NetworkCapabilities()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+        doReturn(new Network[]{mNetwork}).when(mCm).getAllNetworks();
+        doReturn(mNetworkCapabilities).when(mCm).getNetworkCapabilities(eq(mNetwork));
+        doReturn(mNetworkInfo).when(mCm).getNetworkInfo(eq(mNetwork));
+        doReturn(true).when(mNetworkInfo).isConnected();
+
+        startActivity();
+        TestContext.waitForMs(100);
+        // verify there is no network request with internet connection
+        verify(mCm, times(0)).requestNetwork(any(), any(), anyInt());
+        // verify captive portal app is launched
+        assertNotNull(getStartedActivityIntent());
+        assertEquals(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN,
+                getStartedActivityIntent().getAction());
+        stopActivity();
+    }
+}
diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/TestContext.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/TestContext.java
new file mode 100644
index 0000000..e50666b
--- /dev/null
+++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/TestContext.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.carrierdefaultapp;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.util.Log;
+
+import java.util.HashMap;
+
+public class TestContext extends ContextWrapper {
+
+    private final String TAG = this.getClass().getSimpleName();
+
+    private HashMap<String, Object> mInjectedSystemServices = new HashMap<>();
+
+    public TestContext(Context base) {
+        super(base);
+    }
+
+    public <S> void injectSystemService(Class<S> cls, S service) {
+        final String name = getSystemServiceName(cls);
+        mInjectedSystemServices.put(name, service);
+    }
+
+    @Override
+    public Context getApplicationContext() {
+        return this;
+    }
+
+    @Override
+    public Object getSystemService(String name) {
+        if (mInjectedSystemServices.containsKey(name)) {
+            Log.d(TAG, "return mocked system service for " + name);
+            return mInjectedSystemServices.get(name);
+        }
+        Log.d(TAG, "return real system service for " + name);
+        return super.getSystemService(name);
+    }
+
+    public static void waitForMs(long ms) {
+        try {
+            Thread.sleep(ms);
+        } catch (InterruptedException e) {
+        }
+    }
+}
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 5b11303..f79cf04 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -100,6 +100,129 @@
         <item>Always use HDCP checking</item>
     </string-array>
 
+
+    <!-- Bluetooth settings -->
+
+    <!-- Titles for Bluetooth Audio Codec selection preference. [CHAR LIMIT=40] -->
+    <string-array name="bluetooth_a2dp_codec_titles">
+        <item>Default</item>
+        <item>SBC</item>
+        <item>aptX</item>
+        <item>aptX-HD</item>
+        <item>LDAC</item>
+    </string-array>
+
+    <!-- Values for Bluetooth Audio Codec selection preference. -->
+    <string-array name="bluetooth_a2dp_codec_values" translatable="false" >
+        <item>1000000</item>
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+        <item>3</item>
+    </string-array>
+
+    <!-- Summaries for Bluetooth Audio Codec selection preference. [CHAR LIMIT=40]-->
+    <string-array name="bluetooth_a2dp_codec_summaries" >
+        <item>Default</item>
+        <item>SBC</item>
+        <item>aptX</item>
+        <item>aptX-HD</item>
+        <item>LDAC</item>
+    </string-array>
+
+    <!-- Titles for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=40] -->
+    <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+        <item>Default</item>
+        <item>44.1 kHz</item>
+        <item>48.0 kHz</item>
+        <item>88.2 kHz</item>
+        <item>96.0 kHz</item>
+    </string-array>
+
+    <!-- Values for Bluetooth Audio Codec Sample Rate selection preference. -->
+    <string-array name="bluetooth_a2dp_codec_sample_rate_values" translatable="false" >
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+        <item>4</item>
+        <item>8</item>
+    </string-array>
+
+    <!-- Summaries for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=40]-->
+    <string-array name="bluetooth_a2dp_codec_sample_rate_summaries" >
+        <item>Default</item>
+        <item>44.1 kHz</item>
+        <item>48.0 kHz</item>
+        <item>88.2 kHz</item>
+        <item>96.0 kHz</item>
+    </string-array>
+
+    <!-- Titles for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=40] -->
+    <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+        <item>Default</item>
+        <item>16 bits/sample</item>
+        <item>24 bits/sample</item>
+        <item>32 bits/sample</item>
+    </string-array>
+
+    <!-- Values for Bluetooth Audio Codec Bits Per Sample selection preference. -->
+    <string-array name="bluetooth_a2dp_codec_bits_per_sample_values" translatable="false" >
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+        <item>4</item>
+    </string-array>
+
+    <!-- Summaries for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=40]-->
+    <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries" >
+        <item>Default</item>
+        <item>16 bits/sample</item>
+        <item>24 bits/sample</item>
+        <item>32 bits/sample</item>
+    </string-array>
+
+    <!-- Titles for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=40] -->
+    <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+        <item>Default</item>
+        <item>Mono</item>
+        <item>Stereo</item>
+    </string-array>
+
+    <!-- Values for Bluetooth Audio Codec Channel Mode selection preference. -->
+    <string-array name="bluetooth_a2dp_codec_channel_mode_values" translatable="false" >
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+    </string-array>
+
+    <!-- Summaries for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=40]-->
+    <string-array name="bluetooth_a2dp_codec_channel_mode_summaries" >
+        <item>Default</item>
+        <item>Mono</item>
+        <item>Stereo</item>
+    </string-array>
+
+    <!-- Titles for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=40] -->
+    <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+        <item>Sound quality preferred (990kbps/909kbps)</item>
+        <item>Standard (660kbps/606kbps)</item>
+        <item>Connection preferred (330kbps/303kbps)</item>
+    </string-array>
+
+    <!-- Values for Bluetooth Audio Codec LDAC Playback Quaility selection preference. -->
+    <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_values" translatable="false" >
+        <item>1000</item>
+        <item>1001</item>
+        <item>1002</item>
+    </string-array>
+
+    <!-- Summaries for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=40]-->
+    <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries" >
+        <item>Sound quality preferred (990kbps/909kbps)</item>
+        <item>Standard (660kbps/606kbps)</item>
+        <item>Connection preferred (330kbps/303kbps)</item>
+    </string-array>
+
     <!-- Titles for logd limit size selection preference. [CHAR LIMIT=14] -->
     <string-array name="select_logd_size_titles">
         <item>Off</item>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 29839e7..f389000 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -428,6 +428,31 @@
     <!-- Setting Checkbox title for disabling Bluetooth absolute volume -->
     <string name="bluetooth_disable_absolute_volume">Disable absolute volume</string>
 
+    <!-- UI debug setting: Select Bluetooth Audio Codec -->
+    <string name="bluetooth_select_a2dp_codec_type">Bluetooth Audio Codec</string>
+    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec -->
+    <string name="bluetooth_select_a2dp_codec_type_dialog_title">Select Preferred Bluetooth A2DP Codec</string>
+
+    <!-- UI debug setting: Select Bluetooth Audio Sample Rate -->
+    <string name="bluetooth_select_a2dp_codec_sample_rate">Bluetooth Audio Sample Rate</string>
+    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec Sample Rate -->
+    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title">Select Preferred Bluetooth A2DP Codec Sample Rate</string>
+
+    <!-- UI debug setting: Select Bluetooth Audio Bits Per Sample -->
+    <string name="bluetooth_select_a2dp_codec_bits_per_sample">Bluetooth Audio Bits Per Sample</string>
+    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec Bits Per Sample -->
+    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title">Select Preferred Bluetooth A2DP Codec Bits Per Sample</string>
+
+    <!-- UI debug setting: Select Bluetooth Audio Channel Mode -->
+    <string name="bluetooth_select_a2dp_codec_channel_mode">Bluetooth Audio Channel Mode</string>
+    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec Channel Mode -->
+    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title">Select Preferred Bluetooth A2DP Codec Channel Mode</string>
+
+    <!-- UI debug setting: Select Bluetooth Audio LDAC Playback Quality -->
+    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality">Bluetooth Audio LDAC Playback Quality</string>
+    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec LDAC Playback Quality -->
+    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title">Select Preferred Bluetooth A2DP Codec LDAC Playback Quality</string>
+
     <!-- setting Checkbox summary whether to show options for wireless display certification  -->
     <string name="wifi_display_certification_summary">Show options for wireless display certification</string>
     <!-- Setting Checkbox summary whether to enable Wifi verbose Logging [CHAR LIMIT=80] -->
diff --git a/packages/SystemUI/res/layout/qs_customize_panel_content.xml b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
index ca0248e..04d0e65 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel_content.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
@@ -27,7 +27,7 @@
 
     <android.support.v7.widget.RecyclerView
         android:id="@android:id/list"
-        android:layout_width="@dimen/notification_panel_width"
+        android:layout_width="match_parent"
         android:layout_height="0dp"
         android:layout_weight="1"
         android:scrollIndicators="top"
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 5c8a6e2..a172e19 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -358,6 +358,11 @@
     private final TouchAnimator.Listener mNonFirstPageListener =
             new TouchAnimator.ListenerAdapter() {
                 @Override
+                public void onAnimationAtEnd() {
+                    mQuickQsPanel.setVisibility(View.INVISIBLE);
+                }
+
+                @Override
                 public void onAnimationStarted() {
                     mQuickQsPanel.setVisibility(View.VISIBLE);
                 }
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 9f01c18..a61743d 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -19,7 +19,7 @@
     system/netd/server/binder
 
 LOCAL_JAVA_LIBRARIES := services.net telephony-common
-LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update
+LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update2
 LOCAL_PROTOC_OPTIMIZE_TYPE := nano
 
 ifneq ($(INCREMENTAL_BUILDS),)
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index adc59de..4f43eac 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -2029,6 +2029,11 @@
             }
 
             writer.flush();
+            if (args.length == 0) {
+              // Add arg to produce output
+              args = new String[1];
+              args[0] = "--print";
+            }
         }
 
         if (mBluetoothBinder == null) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 66f5c4d..b3627ad 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -883,7 +883,7 @@
 
     private void handleMobileDataAlwaysOn() {
         final boolean enable = (Settings.Global.getInt(
-                mContext.getContentResolver(), Settings.Global.MOBILE_DATA_ALWAYS_ON, 0) == 1);
+                mContext.getContentResolver(), Settings.Global.MOBILE_DATA_ALWAYS_ON, 1) == 1);
         final boolean isEnabled = (mNetworkRequests.get(mDefaultMobileDataRequest) != null);
         if (enable == isEnabled) {
             return;  // Nothing to do.
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 74ff41c..6296375 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -154,7 +154,8 @@
 3110 unknown_sources_enabled (value|1)
 # Package Manager critical info
 3120 pm_critical_info (msg|3)
-
+# Disk usage stats for verifying quota correctness
+3121 pm_package_stats (manual_time|2|3),(quota_time|2|3),(manual_data|2|2),(quota_data|2|2),(manual_cache|2|2),(quota_cache|2|2)
 
 # ---------------------------
 # WindowManagerService.java
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index b9a4831..4cc2931 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -46,6 +46,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.content.res.ObbInfo;
+import android.net.TrafficStats;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.DropBoxManager;
@@ -86,6 +87,7 @@
 import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.TimeUtils;
 import android.util.Xml;
@@ -3738,6 +3740,18 @@
 
             pw.println();
             pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
+            final Pair<String, Long> pair = StorageManager.getPrimaryStoragePathAndSize();
+            if (pair == null) {
+                pw.println("Internal storage total size: N/A");
+            } else {
+                pw.print("Internal storage (");
+                pw.print(pair.first);
+                pw.print(") total size: ");
+                pw.print(pair.second);
+                pw.print(" (");
+                pw.print((float) pair.second / TrafficStats.GB_IN_BYTES);
+                pw.println(" GB)");
+            }
             pw.println("Force adoptable: " + mForceAdoptable);
             pw.println();
             pw.println("Local unlocked users: " + Arrays.toString(mLocalUnlockedUsers));
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 8f16504..158527d 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1905,31 +1905,6 @@
     }
 
     @Override
-    public void setDnsServersForNetwork(int netId, String[] servers, String domains) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
-        Command cmd;
-        if (servers.length > 0) {
-            cmd = new Command("resolver", "setnetdns", netId,
-                    (domains == null ? "" : domains));
-            for (String s : servers) {
-                InetAddress a = NetworkUtils.numericToInetAddress(s);
-                if (a.isAnyLocalAddress() == false) {
-                    cmd.appendArg(a.getHostAddress());
-                }
-            }
-        } else {
-            cmd = new Command("resolver", "clearnetdns", netId);
-        }
-
-        try {
-            mConnector.execute(cmd);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-    }
-
-    @Override
     public void addVpnUidRanges(int netId, UidRange[] ranges) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 983d039..e23844c 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -34,9 +34,9 @@
 import android.net.INetworkScoreCache;
 import android.net.INetworkScoreService;
 import android.net.NetworkKey;
+import android.net.NetworkScoreManager;
 import android.net.NetworkScorerAppManager;
 import android.net.NetworkScorerAppManager.NetworkScorerAppData;
-import android.net.NetworkScoreManager;
 import android.net.RecommendationRequest;
 import android.net.RecommendationResult;
 import android.net.ScoredNetwork;
@@ -301,7 +301,8 @@
 
                 // If we're not connected at all then create a new connection.
                 if (mServiceConnection == null) {
-                    mServiceConnection = new ScoringServiceConnection(componentName);
+                    mServiceConnection = new ScoringServiceConnection(componentName,
+                            scorerData.packageUid);
                 }
 
                 // Make sure the connection is connected (idempotent)
@@ -325,7 +326,7 @@
 
     @Override
     public boolean updateScores(ScoredNetwork[] networks) {
-        if (!mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid())) {
+        if (!isCallerActiveScorer(getCallingUid())) {
             throw new SecurityException("Caller with UID " + getCallingUid() +
                     " is not the active scorer.");
         }
@@ -380,13 +381,16 @@
         }
     }
 
+    private boolean isCallerSystemUid() {
+        // REQUEST_NETWORK_SCORES is a signature only permission.
+        return mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES) ==
+                 PackageManager.PERMISSION_GRANTED;
+    }
+
     @Override
     public boolean clearScores() {
-        // Only the active scorer or the system (who can broadcast BROADCAST_NETWORK_PRIVILEGED)
-        // should be allowed to flush all scores.
-        if (mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid()) ||
-                mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED) ==
-                        PackageManager.PERMISSION_GRANTED) {
+        // Only the active scorer or the system should be allowed to flush all scores.
+        if (isCallerActiveScorer(getCallingUid()) || isCallerSystemUid()) {
             final long token = Binder.clearCallingIdentity();
             try {
                 clearInternal();
@@ -409,20 +413,45 @@
         // In the future, should this API be opened to 3p apps, we will need to lock this down and
         // figure out another way to streamline the UX.
 
-        // mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
         mContext.enforceCallingOrSelfPermission(permission.SCORE_NETWORKS, TAG);
 
         // Scorers (recommendation providers) are selected and no longer set.
         return false;
     }
 
+    /**
+     * Determine whether the application with the given UID is the enabled scorer.
+     *
+     * @param callingUid the UID to check
+     * @return true if the provided UID is the active scorer, false otherwise.
+     */
+    @Override
+    public boolean isCallerActiveScorer(int callingUid) {
+        synchronized (mServiceConnectionLock) {
+            return mServiceConnection != null && mServiceConnection.mScoringAppUid == callingUid;
+        }
+    }
+
+    /**
+     * Obtain the package name of the current active network scorer.
+     *
+     * @return the full package name of the current active scorer, or null if there is no active
+     *         scorer.
+     */
+    @Override
+    public String getActiveScorerPackage() {
+        synchronized (mServiceConnectionLock) {
+            if (mServiceConnection != null) {
+                return mServiceConnection.mComponentName.getPackageName();
+            }
+        }
+        return null;
+    }
+
     @Override
     public void disableScoring() {
-        // Only the active scorer or the system (who can broadcast BROADCAST_NETWORK_PRIVILEGED)
-        // should be allowed to disable scoring.
-        if (mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid()) ||
-                mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED) ==
-                        PackageManager.PERMISSION_GRANTED) {
+        // Only the active scorer or the system should be allowed to disable scoring.
+        if (isCallerActiveScorer(getCallingUid()) || isCallerSystemUid()) {
             // no-op for now but we could write to the setting if needed.
         } else {
             throw new SecurityException(
@@ -450,7 +479,7 @@
     public void registerNetworkScoreCache(int networkType,
                                           INetworkScoreCache scoreCache,
                                           int filterType) {
-        mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
+        mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES, TAG);
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mScoreCaches) {
@@ -475,7 +504,7 @@
 
     @Override
     public void unregisterNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
-        mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
+        mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES, TAG);
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mScoreCaches) {
@@ -496,7 +525,7 @@
 
     @Override
     public RecommendationResult requestRecommendation(RecommendationRequest request) {
-        mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
+        mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES, TAG);
         throwIfCalledOnMainThread();
         final long token = Binder.clearCallingIdentity();
         try {
@@ -526,7 +555,7 @@
 
     @Override
     public boolean requestScores(NetworkKey[] networks) {
-        mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
+        mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES, TAG);
         final long token = Binder.clearCallingIdentity();
         try {
             final INetworkRecommendationProvider provider = getRecommendationProvider();
@@ -624,12 +653,14 @@
 
     private static class ScoringServiceConnection implements ServiceConnection {
         private final ComponentName mComponentName;
+        private final int mScoringAppUid;
         private volatile boolean mBound = false;
         private volatile boolean mConnected = false;
         private volatile INetworkRecommendationProvider mRecommendationProvider;
 
-        ScoringServiceConnection(ComponentName componentName) {
+        ScoringServiceConnection(ComponentName componentName, int scoringAppUid) {
             mComponentName = componentName;
+            mScoringAppUid = scoringAppUid;
         }
 
         void connect(Context context) {
diff --git a/services/core/java/com/android/server/RecoverySystemService.java b/services/core/java/com/android/server/RecoverySystemService.java
index 3c8c699..2010e64 100644
--- a/services/core/java/com/android/server/RecoverySystemService.java
+++ b/services/core/java/com/android/server/RecoverySystemService.java
@@ -181,7 +181,7 @@
         }
 
         @Override // Binder call
-        public void rebootRecoveryWithCommand(String command) {
+        public void rebootRecoveryWithCommand(String command, boolean update) {
             if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
             synchronized (sRequestLock) {
                 if (!setupOrClearBcb(true, command)) {
@@ -190,7 +190,10 @@
 
                 // Having set up the BCB, go ahead and reboot.
                 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-                pm.reboot(PowerManager.REBOOT_RECOVERY);
+                // PowerManagerService may additionally request uncrypting the package when it's
+                // to install an update (REBOOT_RECOVERY_UPDATE).
+                pm.reboot(update ? PowerManager.REBOOT_RECOVERY_UPDATE :
+                        PowerManager.REBOOT_RECOVERY);
             }
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5b02c79..bc03901 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3729,13 +3729,14 @@
                  * resources like shared libraries and access user-wide resources
                  */
                 if (ArrayUtils.isEmpty(permGids)) {
-                    gids = new int[2];
+                    gids = new int[3];
                 } else {
-                    gids = new int[permGids.length + 2];
-                    System.arraycopy(permGids, 0, gids, 2, permGids.length);
+                    gids = new int[permGids.length + 3];
+                    System.arraycopy(permGids, 0, gids, 3, permGids.length);
                 }
                 gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
-                gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid));
+                gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
+                gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));
             }
             checkTime(startTime, "startProcess: building args");
             if (mFactoryTest != FactoryTest.FACTORY_TEST_OFF) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 7fe6c3e..5d619c1 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -225,6 +225,7 @@
     private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
     private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
     private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
+    private static final int MSG_A2DP_DEVICE_CONFIG_CHANGE = 103;
     // end of messages handled under wakelock
 
     private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
@@ -3146,7 +3147,7 @@
                             queueMsgUnderWakeLock(mAudioHandler,
                                     MSG_SET_A2DP_SINK_CONNECTION_STATE,
                                     state,
-                                    0,
+                                    0 /* arg2 unused */,
                                     btDevice,
                                     delay);
                         }
@@ -3163,7 +3164,7 @@
                         queueMsgUnderWakeLock(mAudioHandler,
                                 MSG_SET_A2DP_SRC_CONNECTION_STATE,
                                 state,
-                                0,
+                                0 /* arg2 unused */,
                                 btDevice,
                                 0 /* delay */);
                     }
@@ -3809,8 +3810,8 @@
             int delay = checkSendBecomingNoisyIntent(type, state);
             queueMsgUnderWakeLock(mAudioHandler,
                     MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
-                    0,
-                    0,
+                    0 /* arg1 unused */,
+                    0 /* arg2 unused */,
                     new WiredDeviceConnectionState(type, state, address, name, caller),
                     delay);
         }
@@ -3833,13 +3834,25 @@
                     (profile == BluetoothProfile.A2DP ?
                         MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
                     state,
-                    0,
+                    0 /* arg2 unused */,
                     device,
                     delay);
         }
         return delay;
     }
 
+    public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device)
+    {
+        synchronized (mConnectedDevices) {
+            queueMsgUnderWakeLock(mAudioHandler,
+                    MSG_A2DP_DEVICE_CONFIG_CHANGE,
+                    0 /* arg1 unused */,
+                    0 /* arg1 unused */,
+                    device,
+                    0 /* delay */);
+        }
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // Inner classes
     ///////////////////////////////////////////////////////////////////////////
@@ -4644,6 +4657,11 @@
                     mAudioEventWakeLock.release();
                     break;
 
+                case MSG_A2DP_DEVICE_CONFIG_CHANGE:
+                    onBluetoothA2dpDeviceConfigChange((BluetoothDevice)msg.obj);
+                    mAudioEventWakeLock.release();
+                    break;
+
                 case MSG_REPORT_NEW_ROUTES: {
                     int N = mRoutesObservers.beginBroadcast();
                     if (N > 0) {
@@ -4866,7 +4884,7 @@
     private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
     {
         if (DEBUG_VOL) {
-            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
+            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice+"state=" + state);
         }
         if (btDevice == null) {
             return;
@@ -4877,9 +4895,9 @@
         }
 
         synchronized (mConnectedDevices) {
-            String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                                           btDevice.getAddress());
-            DeviceListSpec deviceSpec = mConnectedDevices.get(key);
+            final String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+                                                 btDevice.getAddress());
+            final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
             boolean isConnected = deviceSpec != null;
 
             if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
@@ -4930,7 +4948,7 @@
     private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
     {
         if (DEBUG_VOL) {
-            Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
+            Log.d(TAG, "onSetA2dpSourceConnectionState btDevice=" + btDevice + " state=" + state);
         }
         if (btDevice == null) {
             return;
@@ -4941,8 +4959,8 @@
         }
 
         synchronized (mConnectedDevices) {
-            String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
-            DeviceListSpec deviceSpec = mConnectedDevices.get(key);
+            final String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
+            final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
             boolean isConnected = deviceSpec != null;
 
             if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
@@ -4953,6 +4971,31 @@
         }
     }
 
+    private void onBluetoothA2dpDeviceConfigChange(BluetoothDevice btDevice)
+    {
+        if (DEBUG_VOL) {
+            Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
+        }
+        if (btDevice == null) {
+            return;
+        }
+        String address = btDevice.getAddress();
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+            address = "";
+        }
+
+        int device = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
+        synchronized (mConnectedDevices) {
+            final String key = makeDeviceListKey(device, address);
+            final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
+            if (deviceSpec != null) {
+                // Device is connected
+                AudioSystem.handleDeviceConfigChange(device, address,
+                        btDevice.getName());
+            }
+        }
+    }
+
     public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
         // address is not used for now, but may be used when multiple a2dp devices are supported
         synchronized (mA2dpAvrcpLock) {
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index ea2cf5f..9ffe2b7 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -80,7 +80,8 @@
  */
 public class NetworkMonitor extends StateMachine {
     private static final String TAG = NetworkMonitor.class.getSimpleName();
-    private static final boolean DBG = false;
+    private static final boolean DBG  = true;
+    private static final boolean VDBG = false;
 
     // Default configuration values for captive portal detection probes.
     // TODO: append a random length parameter to the default HTTPS url.
@@ -432,6 +433,8 @@
                             }));
                     intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL,
                             mLastPortalProbeResult.detectUrl);
+                    intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT,
+                            getCaptivePortalUserAgent(mContext));
                     intent.setFlags(
                             Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
                     mContext.startActivityAsUser(intent, UserHandle.CURRENT);
@@ -954,7 +957,7 @@
                     latencyBroadcast.putExtra(EXTRA_SSID, currentWifiInfo.getSSID());
                     latencyBroadcast.putExtra(EXTRA_BSSID, currentWifiInfo.getBSSID());
                 } else {
-                    if (DBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
+                    if (VDBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
                     return;
                 }
                 break;
@@ -967,8 +970,8 @@
                     if (cellInfo.isRegistered()) {
                         numRegisteredCellInfo++;
                         if (numRegisteredCellInfo > 1) {
-                            log("more than one registered CellInfo.  Can't " +
-                                    "tell which is active.  Bailing.");
+                            if (VDBG) logw("more than one registered CellInfo." +
+                                    " Can't tell which is active.  Bailing.");
                             return;
                         }
                         if (cellInfo instanceof CellInfoCdma) {
@@ -984,7 +987,7 @@
                             CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity();
                             latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
                         } else {
-                            if (DBG) logw("Registered cellinfo is unrecognized");
+                            if (VDBG) logw("Registered cellinfo is unrecognized");
                             return;
                         }
                     }
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index f7b01be..c6bf4c5 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -114,7 +114,7 @@
         }
 
         if (DBG) {
-            Slog.d(TAG, "showNotification " + notifyType
+            Slog.d(TAG, "showNotification id=" + id + " " + notifyType
                     + " transportType=" + getTransportName(transportType)
                     + " extraInfo=" + extraInfo + " highPriority=" + highPriority);
         }
@@ -187,7 +187,7 @@
         try {
             mNotificationManager.notifyAsUser(NOTIFICATION_ID, id, notification, UserHandle.ALL);
         } catch (NullPointerException npe) {
-            Slog.d(TAG, "setNotificationVisible: visible notificationManager npe=" + npe);
+            Slog.d(TAG, "setNotificationVisible: visible notificationManager error", npe);
         }
     }
 
@@ -198,7 +198,7 @@
         try {
             mNotificationManager.cancelAsUser(NOTIFICATION_ID, id, UserHandle.ALL);
         } catch (NullPointerException npe) {
-            Slog.d(TAG, "setNotificationVisible: cancel notificationManager npe=" + npe);
+            Slog.d(TAG, "setNotificationVisible: cancel notificationManager error", npe);
         }
     }
 
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 6d96a10..0c80166 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -32,7 +32,6 @@
 import android.content.res.Resources;
 import android.hardware.usb.UsbManager;
 import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
 import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
 import android.net.LinkProperties;
@@ -73,6 +72,7 @@
 import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
 import com.android.server.connectivity.tethering.IPv6TetheringInterfaceServices;
 import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
+import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
 import com.android.server.net.BaseNetworkObserver;
 
 import java.io.FileDescriptor;
@@ -199,7 +199,8 @@
         mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
         mTetherMasterSM.start();
 
-        mUpstreamNetworkMonitor = new UpstreamNetworkMonitor();
+        mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
+                mContext, mTetherMasterSM, TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
 
         mStateReceiver = new StateReceiver();
         IntentFilter filter = new IntentFilter();
@@ -519,8 +520,8 @@
     }
 
     /**
-     * Creates a proxy {@link ResultReceiver} which enables tethering if the provsioning result is
-     * successful before firing back up to the wrapped receiver.
+     * Creates a proxy {@link ResultReceiver} which enables tethering if the provisioning result
+     * is successful before firing back up to the wrapped receiver.
      *
      * @param type The type of tethering being enabled.
      * @param receiver A ResultReceiver which will be called back with an int resultCode.
@@ -889,7 +890,11 @@
 
     public int setUsbTethering(boolean enable) {
         if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");
-        UsbManager usbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);
+        UsbManager usbManager = mContext.getSystemService(UsbManager.class);
+        if (usbManager == null) {
+            return enable ? ConnectivityManager.TETHER_ERROR_MASTER_ERROR
+                          : ConnectivityManager.TETHER_ERROR_NO_ERROR;
+        }
 
         synchronized (mPublicSync) {
             if (enable) {
@@ -935,7 +940,7 @@
 
     private void checkDunRequired() {
         int secureSetting = 2;
-        TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
         if (tm != null) {
             secureSetting = tm.getTetherApnRequired();
         }
@@ -1026,181 +1031,6 @@
         }
     }
 
-    /**
-     * A NetworkCallback class that relays information of interest to the
-     * tethering master state machine thread for subsequent processing.
-     */
-    class UpstreamNetworkCallback extends NetworkCallback {
-        @Override
-        public void onAvailable(Network network) {
-            mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
-                    UpstreamNetworkMonitor.EVENT_ON_AVAILABLE, 0, network);
-        }
-
-        @Override
-        public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
-            mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
-                    UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES, 0,
-                    new NetworkState(null, null, newNc, network, null, null));
-        }
-
-        @Override
-        public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
-            mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
-                    UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES, 0,
-                    new NetworkState(null, newLp, null, network, null, null));
-        }
-
-        @Override
-        public void onLost(Network network) {
-            mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
-                    UpstreamNetworkMonitor.EVENT_ON_LOST, 0, network);
-        }
-    }
-
-    /**
-     * A class to centralize all the network and link properties information
-     * pertaining to the current and any potential upstream network.
-     *
-     * Calling #start() registers two callbacks: one to track the system default
-     * network and a second to specifically observe TYPE_MOBILE_DUN networks.
-     *
-     * The methods and data members of this class are only to be accessed and
-     * modified from the tethering master state machine thread. Any other
-     * access semantics would necessitate the addition of locking.
-     *
-     * TODO: Investigate whether more "upstream-specific" logic/functionality
-     * could/should be moved here.
-     */
-    class UpstreamNetworkMonitor {
-        static final int EVENT_ON_AVAILABLE      = 1;
-        static final int EVENT_ON_CAPABILITIES   = 2;
-        static final int EVENT_ON_LINKPROPERTIES = 3;
-        static final int EVENT_ON_LOST           = 4;
-
-        final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
-        NetworkCallback mDefaultNetworkCallback;
-        NetworkCallback mDunTetheringCallback;
-
-        void start() {
-            stop();
-
-            mDefaultNetworkCallback = new UpstreamNetworkCallback();
-            getConnectivityManager().registerDefaultNetworkCallback(mDefaultNetworkCallback);
-
-            final NetworkRequest dunTetheringRequest = new NetworkRequest.Builder()
-                    .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-                    .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
-                    .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
-                    .build();
-            mDunTetheringCallback = new UpstreamNetworkCallback();
-            getConnectivityManager().registerNetworkCallback(
-                    dunTetheringRequest, mDunTetheringCallback);
-        }
-
-        void stop() {
-            if (mDefaultNetworkCallback != null) {
-                getConnectivityManager().unregisterNetworkCallback(mDefaultNetworkCallback);
-                mDefaultNetworkCallback = null;
-            }
-
-            if (mDunTetheringCallback != null) {
-                getConnectivityManager().unregisterNetworkCallback(mDunTetheringCallback);
-                mDunTetheringCallback = null;
-            }
-
-            mNetworkMap.clear();
-        }
-
-        NetworkState lookup(Network network) {
-            return (network != null) ? mNetworkMap.get(network) : null;
-        }
-
-        NetworkState processCallback(int arg1, Object obj) {
-            switch (arg1) {
-                case EVENT_ON_AVAILABLE: {
-                    final Network network = (Network) obj;
-                    if (VDBG) {
-                        Log.d(TAG, "EVENT_ON_AVAILABLE for " + network);
-                    }
-                    if (!mNetworkMap.containsKey(network)) {
-                        mNetworkMap.put(network,
-                                new NetworkState(null, null, null, network, null, null));
-                    }
-
-                    final ConnectivityManager cm = getConnectivityManager();
-
-                    if (mDefaultNetworkCallback != null) {
-                        cm.requestNetworkCapabilities(mDefaultNetworkCallback);
-                        cm.requestLinkProperties(mDefaultNetworkCallback);
-                    }
-
-                    // Requesting updates for mDunTetheringCallback is not
-                    // necessary. Because it's a listen, it will already have
-                    // heard all NetworkCapabilities and LinkProperties updates
-                    // since UpstreamNetworkMonitor was started. Because we
-                    // start UpstreamNetworkMonitor before chooseUpstreamType()
-                    // is ever invoked (it can register a DUN request) this is
-                    // mostly safe. However, if a DUN network is already up for
-                    // some reason (unlikely, because DUN is restricted and,
-                    // unless the DUN network is shared with another APN, only
-                    // the system can request it and this is the only part of
-                    // the system that requests it) we won't know its
-                    // LinkProperties or NetworkCapabilities.
-
-                    return mNetworkMap.get(network);
-                }
-                case EVENT_ON_CAPABILITIES: {
-                    final NetworkState ns = (NetworkState) obj;
-                    if (!mNetworkMap.containsKey(ns.network)) {
-                        // Ignore updates for networks for which we have not yet
-                        // received onAvailable() - which should never happen -
-                        // or for which we have already received onLost().
-                        return null;
-                    }
-                    if (VDBG) {
-                        Log.d(TAG, String.format("EVENT_ON_CAPABILITIES for %s: %s",
-                                ns.network, ns.networkCapabilities));
-                    }
-
-                    final NetworkState prev = mNetworkMap.get(ns.network);
-                    mNetworkMap.put(ns.network,
-                            new NetworkState(null, prev.linkProperties, ns.networkCapabilities,
-                                             ns.network, null, null));
-                    return mNetworkMap.get(ns.network);
-                }
-                case EVENT_ON_LINKPROPERTIES: {
-                    final NetworkState ns = (NetworkState) obj;
-                    if (!mNetworkMap.containsKey(ns.network)) {
-                        // Ignore updates for networks for which we have not yet
-                        // received onAvailable() - which should never happen -
-                        // or for which we have already received onLost().
-                        return null;
-                    }
-                    if (VDBG) {
-                        Log.d(TAG, String.format("EVENT_ON_LINKPROPERTIES for %s: %s",
-                                ns.network, ns.linkProperties));
-                    }
-
-                    final NetworkState prev = mNetworkMap.get(ns.network);
-                    mNetworkMap.put(ns.network,
-                            new NetworkState(null, ns.linkProperties, prev.networkCapabilities,
-                                             ns.network, null, null));
-                    return mNetworkMap.get(ns.network);
-                }
-                case EVENT_ON_LOST: {
-                    final Network network = (Network) obj;
-                    if (VDBG) {
-                        Log.d(TAG, "EVENT_ON_LOST for " + network);
-                    }
-                    return mNetworkMap.remove(network);
-                }
-                default:
-                    return null;
-            }
-        }
-    }
-
     // Needed because the canonical source of upstream truth is just the
     // upstream interface name, |mCurrentUpstreamIface|.  This is ripe for
     // future simplification, once the upstream Network is canonical.
@@ -1253,8 +1083,7 @@
         private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
         private final IPv6TetheringCoordinator mIPv6TetheringCoordinator;
 
-        private int mMobileApnReserved = ConnectivityManager.TYPE_NONE;
-        private NetworkCallback mMobileUpstreamCallback;
+        private int mPreviousMobileApn = ConnectivityManager.TYPE_NONE;
 
         private static final int UPSTREAM_SETTLE_TIME_MS     = 10000;
 
@@ -1292,13 +1121,13 @@
             protected boolean turnOnUpstreamMobileConnection(int apnType) {
                 if (apnType == ConnectivityManager.TYPE_NONE) { return false; }
 
-                if (apnType != mMobileApnReserved) {
+                if (apnType != mPreviousMobileApn) {
                     // Unregister any previous mobile upstream callback because
                     // this request, if any, will be different.
                     turnOffUpstreamMobileConnection();
                 }
 
-                if (mMobileUpstreamCallback != null) {
+                if (mUpstreamNetworkMonitor.mobileNetworkRequested()) {
                     // Looks like we already filed a request for this apnType.
                     return true;
                 }
@@ -1307,42 +1136,25 @@
                     case ConnectivityManager.TYPE_MOBILE_DUN:
                     case ConnectivityManager.TYPE_MOBILE:
                     case ConnectivityManager.TYPE_MOBILE_HIPRI:
-                        mMobileApnReserved = apnType;
+                        mPreviousMobileApn = apnType;
                         break;
                     default:
                         return false;
                 }
 
-                final NetworkRequest.Builder builder = new NetworkRequest.Builder()
-                        .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-                if (apnType == ConnectivityManager.TYPE_MOBILE_DUN) {
-                    builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
-                           .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
-                } else {
-                    builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
-                }
-                final NetworkRequest mobileUpstreamRequest = builder.build();
+                // TODO: This should be called by the code that observes
+                // configuration changes, once the above code in this function
+                // is simplified (i.e. eradicated).
+                mUpstreamNetworkMonitor.mobileUpstreamRequiresDun(
+                        apnType == ConnectivityManager.TYPE_MOBILE_DUN);
 
-                // The UpstreamNetworkMonitor's callback will be notified.
-                // Therefore, to avoid duplicate notifications, we only register a no-op.
-                mMobileUpstreamCallback = new NetworkCallback();
-
-                // TODO: Change the timeout from 0 (no onUnavailable callback) to use some
-                // moderate callback time (once timeout callbacks are implemented). This might
-                // be useful for updating some UI. Additionally, we should definitely log a
-                // message to aid in any subsequent debugging
-                if (DBG) Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
-                getConnectivityManager().requestNetwork(
-                        mobileUpstreamRequest, mMobileUpstreamCallback, 0, apnType);
+                mUpstreamNetworkMonitor.registerMobileNetworkRequest();
                 return true;
             }
 
             protected void turnOffUpstreamMobileConnection() {
-                if (mMobileUpstreamCallback != null) {
-                    getConnectivityManager().unregisterNetworkCallback(mMobileUpstreamCallback);
-                    mMobileUpstreamCallback = null;
-                }
-                mMobileApnReserved = ConnectivityManager.TYPE_NONE;
+                mUpstreamNetworkMonitor.releaseMobileNetworkRequest();
+                mPreviousMobileApn = ConnectivityManager.TYPE_NONE;
             }
 
             protected boolean turnOnMasterTetherSettings() {
@@ -1658,7 +1470,6 @@
 
             @Override
             public void exit() {
-                // TODO: examine if we should check the return value.
                 turnOffUpstreamMobileConnection();
                 mUpstreamNetworkMonitor.stop();
                 stopListeningForSimChanges();
@@ -1715,9 +1526,7 @@
                         mTryCell = !mTryCell;
                         break;
                     case EVENT_UPSTREAM_CALLBACK: {
-                        // First: always update local state about every network.
-                        final NetworkState ns = mUpstreamNetworkMonitor.processCallback(
-                                message.arg1, message.obj);
+                        final NetworkState ns = (NetworkState) message.obj;
 
                         if (ns == null || !pertainsToCurrentUpstream(ns)) {
                             // TODO: In future, this is where upstream evaluation and selection
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index afc6247..a5876dd 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1586,9 +1586,6 @@
         public void exit() {
             // We assume that everything is reset after stopping the daemons.
             interrupt();
-            for (LocalSocket socket : mSockets) {
-                IoUtils.closeQuietly(socket);
-            }
             agentDisconnect();
             try {
                 mContext.unregisterReceiver(mBroadcastReceiver);
@@ -1601,8 +1598,26 @@
             Log.v(TAG, "Waiting");
             synchronized (TAG) {
                 Log.v(TAG, "Executing");
-                execute();
-                monitorDaemons();
+                try {
+                    execute();
+                    monitorDaemons();
+                    interrupted(); // Clear interrupt flag if execute called exit.
+                } catch (InterruptedException e) {
+                } finally {
+                    for (LocalSocket socket : mSockets) {
+                        IoUtils.closeQuietly(socket);
+                    }
+                    // This sleep is necessary for racoon to successfully complete sending delete
+                    // message to server.
+                    try {
+                        Thread.sleep(50);
+                    } catch (InterruptedException e) {
+                    }
+                    for (String daemon : mDaemons) {
+                        SystemService.stop(daemon);
+                    }
+                }
+                agentDisconnect();
             }
         }
 
@@ -1801,18 +1816,6 @@
                 Log.i(TAG, "Aborting", e);
                 updateState(DetailedState.FAILED, e.getMessage());
                 exit();
-            } finally {
-                // Kill the daemons if they fail to stop.
-                if (!initFinished) {
-                    for (String daemon : mDaemons) {
-                        SystemService.stop(daemon);
-                    }
-                }
-
-                // Do not leave an unstable state.
-                if (!initFinished || mNetworkInfo.getDetailedState() == DetailedState.CONNECTING) {
-                    agentDisconnect();
-                }
             }
         }
 
@@ -1820,28 +1823,17 @@
          * Monitor the daemons we started, moving to disconnected state if the
          * underlying services fail.
          */
-        private void monitorDaemons() {
+        private void monitorDaemons() throws InterruptedException{
             if (!mNetworkInfo.isConnected()) {
                 return;
             }
-
-            try {
-                while (true) {
-                    Thread.sleep(2000);
-                    for (int i = 0; i < mDaemons.length; i++) {
-                        if (mArguments[i] != null && SystemService.isStopped(mDaemons[i])) {
-                            return;
-                        }
+            while (true) {
+                Thread.sleep(2000);
+                for (int i = 0; i < mDaemons.length; i++) {
+                    if (mArguments[i] != null && SystemService.isStopped(mDaemons[i])) {
+                        return;
                     }
                 }
-            } catch (InterruptedException e) {
-                Log.d(TAG, "interrupted during monitorDaemons(); stopping services");
-            } finally {
-                for (String daemon : mDaemons) {
-                    SystemService.stop(daemon);
-                }
-
-                agentDisconnect();
             }
         }
     }
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
new file mode 100644
index 0000000..927dfd5
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.net.NetworkState;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.StateMachine;
+
+import java.util.HashMap;
+
+
+/**
+ * A class to centralize all the network and link properties information
+ * pertaining to the current and any potential upstream network.
+ *
+ * Calling #start() registers two callbacks: one to track the system default
+ * network and a second to specifically observe TYPE_MOBILE_DUN networks.
+ *
+ * The methods and data members of this class are only to be accessed and
+ * modified from the tethering master state machine thread. Any other
+ * access semantics would necessitate the addition of locking.
+ *
+ * TODO: Move upstream selection logic here.
+ *
+ * @hide
+ */
+public class UpstreamNetworkMonitor {
+    private static final String TAG = UpstreamNetworkMonitor.class.getSimpleName();
+    private static final boolean DBG = false;
+    private static final boolean VDBG = false;
+
+    public static final int EVENT_ON_AVAILABLE      = 1;
+    public static final int EVENT_ON_CAPABILITIES   = 2;
+    public static final int EVENT_ON_LINKPROPERTIES = 3;
+    public static final int EVENT_ON_LOST           = 4;
+
+    private final Context mContext;
+    private final StateMachine mTarget;
+    private final int mWhat;
+    private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
+    private ConnectivityManager mCM;
+    private NetworkCallback mDefaultNetworkCallback;
+    private NetworkCallback mDunTetheringCallback;
+    private NetworkCallback mMobileNetworkCallback;
+    private boolean mDunRequired;
+
+    public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, int what) {
+        mContext = ctx;
+        mTarget = tgt;
+        mWhat = what;
+    }
+
+    @VisibleForTesting
+    public UpstreamNetworkMonitor(StateMachine tgt, int what, ConnectivityManager cm) {
+        this(null, tgt, what);
+        mCM = cm;
+    }
+
+    public void start() {
+        stop();
+
+        mDefaultNetworkCallback = new UpstreamNetworkCallback();
+        cm().registerDefaultNetworkCallback(mDefaultNetworkCallback);
+
+        final NetworkRequest dunTetheringRequest = new NetworkRequest.Builder()
+                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
+                .build();
+        mDunTetheringCallback = new UpstreamNetworkCallback();
+        cm().registerNetworkCallback(dunTetheringRequest, mDunTetheringCallback);
+    }
+
+    public void stop() {
+        releaseMobileNetworkRequest();
+
+        releaseCallback(mDefaultNetworkCallback);
+        mDefaultNetworkCallback = null;
+
+        releaseCallback(mDunTetheringCallback);
+        mDunTetheringCallback = null;
+
+        mNetworkMap.clear();
+    }
+
+    public void mobileUpstreamRequiresDun(boolean dunRequired) {
+        final boolean valueChanged = (mDunRequired != dunRequired);
+        mDunRequired = dunRequired;
+        if (valueChanged && mobileNetworkRequested()) {
+            releaseMobileNetworkRequest();
+            registerMobileNetworkRequest();
+        }
+    }
+
+    public boolean mobileNetworkRequested() {
+        return (mMobileNetworkCallback != null);
+    }
+
+    public void registerMobileNetworkRequest() {
+        if (mMobileNetworkCallback != null) return;
+
+        final NetworkRequest.Builder builder = new NetworkRequest.Builder()
+                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+        if (mDunRequired) {
+            builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                   .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
+        } else {
+            builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+        }
+        final NetworkRequest mobileUpstreamRequest = builder.build();
+
+        // The existing default network and DUN callbacks will be notified.
+        // Therefore, to avoid duplicate notifications, we only register a no-op.
+        mMobileNetworkCallback = new NetworkCallback();
+
+        // TODO: Change the timeout from 0 (no onUnavailable callback) to use some
+        // moderate callback time (once timeout callbacks are implemented). This might
+        // be useful for updating some UI. Additionally, we should definitely log a
+        // message to aid in any subsequent debugging
+        if (DBG) Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
+
+        cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback);
+    }
+
+    public void releaseMobileNetworkRequest() {
+        if (mMobileNetworkCallback == null) return;
+
+        cm().unregisterNetworkCallback(mMobileNetworkCallback);
+        mMobileNetworkCallback = null;
+    }
+
+    public NetworkState lookup(Network network) {
+        return (network != null) ? mNetworkMap.get(network) : null;
+    }
+
+    private void handleAvailable(Network network) {
+        if (VDBG) {
+            Log.d(TAG, "EVENT_ON_AVAILABLE for " + network);
+        }
+        if (!mNetworkMap.containsKey(network)) {
+            mNetworkMap.put(network,
+                    new NetworkState(null, null, null, network, null, null));
+        }
+
+        final ConnectivityManager cm = cm();
+
+        if (mDefaultNetworkCallback != null) {
+            cm.requestNetworkCapabilities(mDefaultNetworkCallback);
+            cm.requestLinkProperties(mDefaultNetworkCallback);
+        }
+
+        // Requesting updates for mDunTetheringCallback is not
+        // necessary. Because it's a listen, it will already have
+        // heard all NetworkCapabilities and LinkProperties updates
+        // since UpstreamNetworkMonitor was started. Because we
+        // start UpstreamNetworkMonitor before chooseUpstreamType()
+        // is ever invoked (it can register a DUN request) this is
+        // mostly safe. However, if a DUN network is already up for
+        // some reason (unlikely, because DUN is restricted and,
+        // unless the DUN network is shared with another APN, only
+        // the system can request it and this is the only part of
+        // the system that requests it) we won't know its
+        // LinkProperties or NetworkCapabilities.
+
+        notifyTarget(EVENT_ON_AVAILABLE, network);
+    }
+
+    private void handleNetCap(Network network, NetworkCapabilities newNc) {
+        if (!mNetworkMap.containsKey(network)) {
+            // Ignore updates for networks for which we have not yet
+            // received onAvailable() - which should never happen -
+            // or for which we have already received onLost().
+            return;
+        }
+        if (VDBG) {
+            Log.d(TAG, String.format("EVENT_ON_CAPABILITIES for %s: %s",
+                    network, newNc));
+        }
+
+        final NetworkState prev = mNetworkMap.get(network);
+        mNetworkMap.put(network,
+                new NetworkState(null, prev.linkProperties, newNc,
+                                 network, null, null));
+        notifyTarget(EVENT_ON_CAPABILITIES, network);
+    }
+
+    private void handleLinkProp(Network network, LinkProperties newLp) {
+        if (!mNetworkMap.containsKey(network)) {
+            // Ignore updates for networks for which we have not yet
+            // received onAvailable() - which should never happen -
+            // or for which we have already received onLost().
+            return;
+        }
+        if (VDBG) {
+            Log.d(TAG, String.format("EVENT_ON_LINKPROPERTIES for %s: %s",
+                    network, newLp));
+        }
+
+        final NetworkState prev = mNetworkMap.get(network);
+        mNetworkMap.put(network,
+                new NetworkState(null, newLp, prev.networkCapabilities,
+                                 network, null, null));
+        notifyTarget(EVENT_ON_LINKPROPERTIES, network);
+    }
+
+    private void handleLost(Network network) {
+        if (!mNetworkMap.containsKey(network)) {
+            // Ignore updates for networks for which we have not yet
+            // received onAvailable() - which should never happen -
+            // or for which we have already received onLost().
+            return;
+        }
+        if (VDBG) {
+            Log.d(TAG, "EVENT_ON_LOST for " + network);
+        }
+        notifyTarget(EVENT_ON_LOST, mNetworkMap.remove(network));
+    }
+
+    // Fetch (and cache) a ConnectivityManager only if and when we need one.
+    private ConnectivityManager cm() {
+        if (mCM == null) {
+            mCM = mContext.getSystemService(ConnectivityManager.class);
+        }
+        return mCM;
+    }
+
+    /**
+     * A NetworkCallback class that relays information of interest to the
+     * tethering master state machine thread for subsequent processing.
+     */
+    private class UpstreamNetworkCallback extends NetworkCallback {
+        @Override
+        public void onAvailable(Network network) {
+            mTarget.getHandler().post(() -> handleAvailable(network));
+        }
+
+        @Override
+        public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
+            mTarget.getHandler().post(() -> handleNetCap(network, newNc));
+        }
+
+        @Override
+        public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
+            mTarget.getHandler().post(() -> handleLinkProp(network, newLp));
+        }
+
+        @Override
+        public void onLost(Network network) {
+            mTarget.getHandler().post(() -> handleLost(network));
+        }
+    }
+
+    private void releaseCallback(NetworkCallback cb) {
+        if (cb != null) cm().unregisterNetworkCallback(cb);
+    }
+
+    private void notifyTarget(int which, Network network) {
+        notifyTarget(which, mNetworkMap.get(network));
+    }
+
+    private void notifyTarget(int which, NetworkState netstate) {
+        mTarget.sendMessage(mWhat, which, 0, netstate);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/AbstractStatsBase.java b/services/core/java/com/android/server/pm/AbstractStatsBase.java
index 612c476..0053f58 100644
--- a/services/core/java/com/android/server/pm/AbstractStatsBase.java
+++ b/services/core/java/com/android/server/pm/AbstractStatsBase.java
@@ -60,12 +60,12 @@
         return new AtomicFile(fname);
     }
 
-    void writeNow(final T data) {
+    protected void writeNow(final T data) {
         writeImpl(data);
         mLastTimeWritten.set(SystemClock.elapsedRealtime());
     }
 
-    boolean maybeWriteAsync(final T data) {
+    protected boolean maybeWriteAsync(final T data) {
         if (SystemClock.elapsedRealtime() - mLastTimeWritten.get() < WRITE_INTERVAL_MS
             && !PackageManagerService.DEBUG_DEXOPT) {
             return false;
@@ -105,7 +105,7 @@
 
     protected abstract void writeInternal(T data);
 
-    void read(T data) {
+    protected void read(T data) {
         if (mLock) {
             synchronized (data) {
                 synchronized (mFileLock) {
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index cec1058..601a219 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -42,12 +42,18 @@
  * {@hide}
  */
 public class BackgroundDexOptService extends JobService {
-    static final String TAG = "BackgroundDexOptService";
+    private static final String TAG = "BackgroundDexOptService";
 
-    static final long RETRY_LATENCY = 4 * AlarmManager.INTERVAL_HOUR;
+    private static final boolean DEBUG = false;
 
-    static final int JOB_IDLE_OPTIMIZE = 800;
-    static final int JOB_POST_BOOT_UPDATE = 801;
+    private static final long RETRY_LATENCY = 4 * AlarmManager.INTERVAL_HOUR;
+
+    private static final int JOB_IDLE_OPTIMIZE = 800;
+    private static final int JOB_POST_BOOT_UPDATE = 801;
+
+    private static final long IDLE_OPTIMIZATION_PERIOD = DEBUG
+            ? TimeUnit.MINUTES.toMillis(1)
+            : TimeUnit.DAYS.toMillis(1);
 
     private static ComponentName sDexoptServiceName = new ComponentName(
             "android",
@@ -69,7 +75,7 @@
      */
     final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false);
 
-    private final File dataDir = Environment.getDataDirectory();
+    private final File mDataDir = Environment.getDataDirectory();
 
     public static void schedule(Context context) {
         JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
@@ -86,7 +92,7 @@
         js.schedule(new JobInfo.Builder(JOB_IDLE_OPTIMIZE, sDexoptServiceName)
                     .setRequiresDeviceIdle(true)
                     .setRequiresCharging(true)
-                    .setPeriodic(TimeUnit.DAYS.toMillis(1))
+                    .setPeriodic(IDLE_OPTIMIZATION_PERIOD)
                     .build());
 
         if (DEBUG_DEXOPT) {
@@ -120,7 +126,7 @@
 
     private long getLowStorageThreshold() {
         @SuppressWarnings("deprecation")
-        final long lowThreshold = StorageManager.from(this).getStorageLowBytes(dataDir);
+        final long lowThreshold = StorageManager.from(this).getStorageLowBytes(mDataDir);
         if (lowThreshold == 0) {
             Log.e(TAG, "Invalid low storage threshold");
         }
@@ -134,114 +140,127 @@
             // This job has already been superseded. Do not start it.
             return false;
         }
-
-        // Load low battery threshold from the system config. This is a 0-100 integer.
-        final int lowBatteryThreshold = getResources().getInteger(
-                com.android.internal.R.integer.config_lowBatteryWarningLevel);
-
-        final long lowThreshold = getLowStorageThreshold();
-
-        mAbortPostBootUpdate.set(false);
         new Thread("BackgroundDexOptService_PostBootUpdate") {
             @Override
             public void run() {
-                for (String pkg : pkgs) {
-                    if (mAbortPostBootUpdate.get()) {
-                        // JobScheduler requested an early abort.
-                        return;
-                    }
-                    if (mExitPostBootUpdate.get()) {
-                        // Different job, which supersedes this one, is running.
-                        break;
-                    }
-                    if (getBatteryLevel() < lowBatteryThreshold) {
-                        // Rather bail than completely drain the battery.
-                        break;
-                    }
-                    long usableSpace = dataDir.getUsableSpace();
-                    if (usableSpace < lowThreshold) {
-                        // Rather bail than completely fill up the disk.
-                        Log.w(TAG, "Aborting background dex opt job due to low storage: " +
-                                usableSpace);
-                        break;
-                    }
+                postBootUpdate(jobParams, pm, pkgs);
+            }
 
-                    if (DEBUG_DEXOPT) {
-                        Log.i(TAG, "Updating package " + pkg);
-                    }
+        }.start();
+        return true;
+    }
 
-                    // Update package if needed. Note that there can be no race between concurrent
-                    // jobs because PackageDexOptimizer.performDexOpt is synchronized.
+    private void postBootUpdate(JobParameters jobParams, PackageManagerService pm,
+            ArraySet<String> pkgs) {
+        // Load low battery threshold from the system config. This is a 0-100 integer.
+        final int lowBatteryThreshold = getResources().getInteger(
+                com.android.internal.R.integer.config_lowBatteryWarningLevel);
+        final long lowThreshold = getLowStorageThreshold();
 
-                    // checkProfiles is false to avoid merging profiles during boot which
-                    // might interfere with background compilation (b/28612421).
-                    // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will
-                    // behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a
-                    // trade-off worth doing to save boot time work.
-                    pm.performDexOpt(pkg,
-                            /* checkProfiles */ false,
-                            PackageManagerService.REASON_BOOT,
-                            /* force */ false);
-                }
-                // Ran to completion, so we abandon our timeslice and do not reschedule.
-                jobFinished(jobParams, /* reschedule */ false);
+        mAbortPostBootUpdate.set(false);
+
+        for (String pkg : pkgs) {
+            if (mAbortPostBootUpdate.get()) {
+                // JobScheduler requested an early abort.
+                return;
+            }
+            if (mExitPostBootUpdate.get()) {
+                // Different job, which supersedes this one, is running.
+                break;
+            }
+            if (getBatteryLevel() < lowBatteryThreshold) {
+                // Rather bail than completely drain the battery.
+                break;
+            }
+            long usableSpace = mDataDir.getUsableSpace();
+            if (usableSpace < lowThreshold) {
+                // Rather bail than completely fill up the disk.
+                Log.w(TAG, "Aborting background dex opt job due to low storage: " +
+                        usableSpace);
+                break;
+            }
+
+            if (DEBUG_DEXOPT) {
+                Log.i(TAG, "Updating package " + pkg);
+            }
+
+            // Update package if needed. Note that there can be no race between concurrent
+            // jobs because PackageDexOptimizer.performDexOpt is synchronized.
+
+            // checkProfiles is false to avoid merging profiles during boot which
+            // might interfere with background compilation (b/28612421).
+            // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will
+            // behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a
+            // trade-off worth doing to save boot time work.
+            pm.performDexOpt(pkg,
+                    /* checkProfiles */ false,
+                    PackageManagerService.REASON_BOOT,
+                    /* force */ false);
+        }
+        // Ran to completion, so we abandon our timeslice and do not reschedule.
+        jobFinished(jobParams, /* reschedule */ false);
+    }
+
+    private boolean runIdleOptimization(final JobParameters jobParams,
+            final PackageManagerService pm, final ArraySet<String> pkgs) {
+        new Thread("BackgroundDexOptService_IdleOptimization") {
+            @Override
+            public void run() {
+                idleOptimization(jobParams, pm, pkgs);
             }
         }.start();
         return true;
     }
 
-    private boolean runIdleOptimization(final JobParameters jobParams,
-            final PackageManagerService pm, final ArraySet<String> pkgs) {
+    private void idleOptimization(JobParameters jobParams, PackageManagerService pm,
+            ArraySet<String> pkgs) {
+        Log.i(TAG, "Performing idle optimizations");
         // If post-boot update is still running, request that it exits early.
         mExitPostBootUpdate.set(true);
 
         mAbortIdleOptimization.set(false);
 
         final long lowThreshold = getLowStorageThreshold();
-
-        new Thread("BackgroundDexOptService_IdleOptimization") {
-            @Override
-            public void run() {
-                for (String pkg : pkgs) {
-                    if (mAbortIdleOptimization.get()) {
-                        // JobScheduler requested an early abort.
-                        return;
-                    }
-                    if (sFailedPackageNames.contains(pkg)) {
-                        // Skip previously failing package
-                        continue;
-                    }
-
-                    long usableSpace = dataDir.getUsableSpace();
-                    if (usableSpace < lowThreshold) {
-                        // Rather bail than completely fill up the disk.
-                        Log.w(TAG, "Aborting background dex opt job due to low storage: " +
-                                usableSpace);
-                        break;
-                    }
-
-                    // Conservatively add package to the list of failing ones in case performDexOpt
-                    // never returns.
-                    synchronized (sFailedPackageNames) {
-                        sFailedPackageNames.add(pkg);
-                    }
-                    // Optimize package if needed. Note that there can be no race between
-                    // concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
-                    if (pm.performDexOpt(pkg,
-                            /* checkProfiles */ true,
-                            PackageManagerService.REASON_BACKGROUND_DEXOPT,
-                            /* force */ false)) {
-                        // Dexopt succeeded, remove package from the list of failing ones.
-                        synchronized (sFailedPackageNames) {
-                            sFailedPackageNames.remove(pkg);
-                        }
-                    }
-                }
-                // Ran to completion, so we abandon our timeslice and do not reschedule.
-                jobFinished(jobParams, /* reschedule */ false);
+        for (String pkg : pkgs) {
+            if (mAbortIdleOptimization.get()) {
+                // JobScheduler requested an early abort.
+                return;
             }
-        }.start();
-        return true;
+
+            synchronized (sFailedPackageNames) {
+                if (sFailedPackageNames.contains(pkg)) {
+                    // Skip previously failing package
+                    continue;
+                }
+            }
+
+            long usableSpace = mDataDir.getUsableSpace();
+            if (usableSpace < lowThreshold) {
+                // Rather bail than completely fill up the disk.
+                Log.w(TAG, "Aborting background dex opt job due to low storage: " +
+                        usableSpace);
+                break;
+            }
+
+            // Conservatively add package to the list of failing ones in case performDexOpt
+            // never returns.
+            synchronized (sFailedPackageNames) {
+                sFailedPackageNames.add(pkg);
+            }
+            // Optimize package if needed. Note that there can be no race between
+            // concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
+            if (pm.performDexOpt(pkg,
+                    /* checkProfiles */ true,
+                    PackageManagerService.REASON_BACKGROUND_DEXOPT,
+                    /* force */ false)) {
+                // Dexopt succeeded, remove package from the list of failing ones.
+                synchronized (sFailedPackageNames) {
+                    sFailedPackageNames.remove(pkg);
+                }
+            }
+        }
+        // Ran to completion, so we abandon our timeslice and do not reschedule.
+        jobFinished(jobParams, /* reschedule */ false);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 5016ec0..a6f9243 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -1013,7 +1013,7 @@
                         permissions.clear();
                     }
                     permissions.add(permissionGrant.name);
-                    grantRuntimePermissionsLPw(pkg, permissions, false,
+                    grantRuntimePermissionsLPw(pkg, permissions,
                             permissionGrant.fixed, userId);
                 }
             }
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 1f83d9e..98249dd1 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -54,6 +54,7 @@
     // NOTE: keep in sync with installd
     public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
     public static final int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
+    public static final int FLAG_USE_QUOTA = 1 << 12;
 
     private final boolean mIsolated;
 
@@ -198,15 +199,44 @@
         }
     }
 
-    public void getAppSize(String uuid, String packageName, int userId, int flags, long ceDataInode,
-            String codePath, PackageStats stats) throws InstallerException {
+    public void getAppSize(String uuid, String[] packageNames, int userId, int flags, int appId,
+            long[] ceDataInodes, String[] codePaths, PackageStats stats)
+            throws InstallerException {
         if (!checkBeforeRemote()) return;
         try {
-            final long[] res = mInstalld.getAppSize(uuid, packageName, userId, flags, ceDataInode,
-                    codePath);
+            final long[] res = mInstalld.getAppSize(uuid, packageNames, userId, flags,
+                    appId, ceDataInodes, codePaths);
             stats.codeSize += res[0];
             stats.dataSize += res[1];
             stats.cacheSize += res[2];
+            stats.externalCodeSize += res[3];
+            stats.externalDataSize += res[4];
+            stats.externalCacheSize += res[5];
+        } catch (Exception e) {
+            throw InstallerException.from(e);
+        }
+    }
+
+    public void getUserSize(String uuid, int userId, int flags, int[] appIds, PackageStats stats)
+            throws InstallerException {
+        if (!checkBeforeRemote()) return;
+        try {
+            final long[] res = mInstalld.getUserSize(uuid, userId, flags, appIds);
+            stats.codeSize += res[0];
+            stats.dataSize += res[1];
+            stats.cacheSize += res[2];
+            stats.externalCodeSize += res[3];
+            stats.externalDataSize += res[4];
+            stats.externalCacheSize += res[5];
+        } catch (Exception e) {
+            throw InstallerException.from(e);
+        }
+    }
+
+    public long[] getExternalSize(String uuid, int userId, int flags) throws InstallerException {
+        if (!checkBeforeRemote()) return new long[4];
+        try {
+            return mInstalld.getExternalSize(uuid, userId, flags);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 30ff32b..aeac7f6 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -217,26 +217,11 @@
                             dexoptNeeded);
                 }
 
-                final String dexoptType;
-                String oatDir = null;
-                boolean isOdexLocation = (dexoptNeeded < 0);
-                switch (Math.abs(dexoptNeeded)) {
-                    case DexFile.NO_DEXOPT_NEEDED:
-                        continue;
-                    case DexFile.DEX2OAT_FROM_SCRATCH:
-                    case DexFile.DEX2OAT_FOR_BOOT_IMAGE:
-                    case DexFile.DEX2OAT_FOR_FILTER:
-                    case DexFile.DEX2OAT_FOR_RELOCATION:
-                        dexoptType = "dex2oat";
-                        oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
-                        break;
-                    case DexFile.PATCHOAT_FOR_RELOCATION:
-                        dexoptType = "patchoat";
-                        break;
-                    default:
-                        throw new IllegalStateException("Invalid dexopt:" + dexoptNeeded);
+                if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
+                    continue;
                 }
 
+                String oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
                 String sharedLibrariesPath = null;
                 if (sharedLibraries != null && sharedLibraries.length != 0) {
                     StringBuilder sb = new StringBuilder();
@@ -248,7 +233,7 @@
                     }
                     sharedLibrariesPath = sb.toString();
                 }
-                Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
+                Log.i(TAG, "Running dexopt on: " + path + " pkg="
                         + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
                         + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
                         + " target-filter=" + targetCompilerFilter + " oatDir = " + oatDir
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7ce5aa8..7a547f0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -253,6 +253,7 @@
 import com.android.server.pm.PermissionsState.PermissionState;
 import com.android.server.pm.Settings.DatabaseVersion;
 import com.android.server.pm.Settings.VersionInfo;
+import com.android.server.pm.dex.DexManager;
 import com.android.server.storage.DeviceStorageMonitorInternal;
 
 import dalvik.system.CloseGuard;
@@ -295,6 +296,7 @@
 import java.util.Comparator;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -370,6 +372,9 @@
     private static final boolean DISABLE_EPHEMERAL_APPS = false;
     private static final boolean HIDE_EPHEMERAL_APIS = true;
 
+    private static final boolean ENABLE_QUOTA =
+            SystemProperties.getBoolean("persist.fw.quota", false);
+
     private static final int RADIO_UID = Process.PHONE_UID;
     private static final int LOG_UID = Process.LOG_UID;
     private static final int NFC_UID = Process.NFC_UID;
@@ -709,6 +714,9 @@
     final PackageInstallerService mInstallerService;
 
     private final PackageDexOptimizer mPackageDexOptimizer;
+    // DexManager handles the usage of dex files (e.g. secondary files, whether or not a package
+    // is used by other apps).
+    private final DexManager mDexManager;
 
     private AtomicInteger mNextMoveId = new AtomicInteger();
     private final MoveCallbacks mMoveCallbacks;
@@ -2113,6 +2121,7 @@
         mInstaller = installer;
         mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
                 "*dexopt*");
+        mDexManager = new DexManager();
         mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
 
         mOnPermissionChangeListeners = new OnPermissionChangeListeners(
@@ -2706,6 +2715,21 @@
             }
 
             mEphemeralApplicationRegistry = new EphemeralApplicationRegistry(this);
+
+            // Read and update the usage of dex files.
+            // Do this at the end of PM init so that all the packages have their
+            // data directory reconciled.
+            // At this point we know the code paths of the packages, so we can validate
+            // the disk file and build the internal cache.
+            // The usage file is expected to be small so loading and verifying it
+            // should take a fairly small time compare to the other activities (e.g. package
+            // scanning).
+            final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();
+            final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
+            for (int userId : currentUserIds) {
+                userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());
+            }
+            mDexManager.load(userPackages);
         } // synchronized (mPackages)
         } // synchronized (mInstallLock)
 
@@ -7362,7 +7386,14 @@
 
     @Override
     public void notifyDexLoad(String loadingPackageName, List<String> dexPaths, String loaderIsa) {
-      // TODO(calin): b/32871170
+        int userId = UserHandle.getCallingUserId();
+        ApplicationInfo ai = getApplicationInfo(loadingPackageName, /*flags*/ 0, userId);
+        if (ai == null) {
+            Slog.w(TAG, "Loading a package that does not exist for the calling user. package="
+                + loadingPackageName + ", user=" + userId);
+            return;
+        }
+        mDexManager.notifyDexLoad(ai, dexPaths, loaderIsa, userId);
     }
 
     // TODO: this is not used nor needed. Delete it.
@@ -16878,20 +16909,28 @@
                 return false;
             }
         }
+
+        final String[] packageNames = { packageName };
+        final long[] ceDataInodes = { ps.getCeDataInode(userId) };
+        final String[] codePaths = { ps.codePathString };
+
         try {
-            mInstaller.getAppSize(ps.volumeUuid, packageName, userId,
-                    StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE,
-                    ps.getCeDataInode(userId), ps.codePathString, stats);
+            mInstaller.getAppSize(ps.volumeUuid, packageNames, userId, 0,
+                    ps.appId, ceDataInodes, codePaths, stats);
+
+            // For now, ignore code size of packages on system partition
+            if (isSystemApp(ps) && !isUpdatedSystemApp(ps)) {
+                stats.codeSize = 0;
+            }
+
+            // External clients expect these to be tracked separately
+            stats.dataSize -= stats.cacheSize;
+
         } catch (InstallerException e) {
             Slog.w(TAG, String.valueOf(e));
             return false;
         }
 
-        // For now, ignore code size of packages on system partition
-        if (isSystemApp(ps) && !isUpdatedSystemApp(ps)) {
-            stats.codeSize = 0;
-        }
-
         return true;
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index cfd0af7..45887e1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -24,11 +24,13 @@
 import android.content.Intent;
 import android.content.pm.PackageParser;
 import android.content.pm.ResolveInfo;
+import android.os.Build;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.system.ErrnoException;
 import android.util.ArraySet;
 import android.util.Log;
+import dalvik.system.VMRuntime;
 import libcore.io.Libcore;
 
 import java.io.File;
@@ -197,4 +199,17 @@
         }
         return sb.toString();
     }
+
+    /**
+     * Verifies that the given string {@code isa} is a valid supported isa on
+     * the running device.
+     */
+    public static boolean checkISA(String isa) {
+        for (String abi : Build.SUPPORTED_ABIS) {
+            if (VMRuntime.getInstructionSet(abi).equals(isa)) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
new file mode 100644
index 0000000..6d06838
--- /dev/null
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.pm.dex;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.ApplicationInfo;
+
+import android.util.Slog;
+
+import com.android.server.pm.PackageManagerServiceUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * This class keeps track of how dex files are used.
+ * Every time it gets a notification about a dex file being loaded it tracks
+ * its owning package and records it in PackageDexUsage (package-dex-usage.list).
+ *
+ * TODO(calin): Extract related dexopt functionality from PackageManagerService
+ * into this class.
+ */
+public class DexManager {
+    private static final String TAG = "DexManager";
+
+    private static final boolean DEBUG = false;
+
+    // Maps package name to code locations.
+    // It caches the code locations for the installed packages. This allows for
+    // faster lookups (no locks) when finding what package owns the dex file.
+    private final Map<String, PackageCodeLocations> mPackageCodeLocationsCache;
+
+    // PackageDexUsage handles the actual I/O operations. It is responsible to
+    // encode and save the dex usage data.
+    private final PackageDexUsage mPackageDexUsage;
+
+    // Possible outcomes of a dex search.
+    private static int DEX_SEARCH_NOT_FOUND = 0;  // dex file not found
+    private static int DEX_SEARCH_FOUND_PRIMARY = 1;  // dex file is the primary/base apk
+    private static int DEX_SEARCH_FOUND_SPLIT = 2;  // dex file is a split apk
+    private static int DEX_SEARCH_FOUND_SECONDARY = 3;  // dex file is a secondary dex
+
+    public DexManager() {
+      mPackageCodeLocationsCache = new HashMap<>();
+      mPackageDexUsage = new PackageDexUsage();
+    }
+
+    /**
+     * Notify about dex files loads.
+     * Note that this method is invoked when apps load dex files and it should
+     * return as fast as possible.
+     *
+     * @param loadingPackage the package performing the load
+     * @param dexPaths the list of dex files being loaded
+     * @param loaderIsa the ISA of the app loading the dex files
+     * @param loaderUserId the user id which runs the code loading the dex files
+     */
+    public void notifyDexLoad(ApplicationInfo loadingAppInfo, List<String> dexPaths,
+            String loaderIsa, int loaderUserId) {
+        try {
+            notifyDexLoadInternal(loadingAppInfo, dexPaths, loaderIsa, loaderUserId);
+        } catch (Exception e) {
+            Slog.w(TAG, "Exception while notifying dex load for package " +
+                    loadingAppInfo.packageName, e);
+        }
+    }
+
+    private void notifyDexLoadInternal(ApplicationInfo loadingAppInfo, List<String> dexPaths,
+            String loaderIsa, int loaderUserId) {
+        if (!PackageManagerServiceUtils.checkISA(loaderIsa)) {
+            Slog.w(TAG, "Loading dex files " + dexPaths + " in unsupported ISA: " +
+                    loaderIsa + "?");
+            return;
+        }
+
+        for (String dexPath : dexPaths) {
+            // Find the owning package name.
+            DexSearchResult searchResult = getDexPackage(loadingAppInfo, dexPath, loaderUserId);
+
+            if (DEBUG) {
+                Slog.i(TAG, loadingAppInfo.packageName
+                    + " loads from " + searchResult + " : " + loaderUserId + " : " + dexPath);
+            }
+
+            if (searchResult.mOutcome != DEX_SEARCH_NOT_FOUND) {
+                // TODO(calin): extend isUsedByOtherApps check to detect the cases where
+                // different apps share the same runtime. In that case we should not mark the dex
+                // file as isUsedByOtherApps. Currently this is a safe approximation.
+                boolean isUsedByOtherApps = !loadingAppInfo.packageName.equals(
+                        searchResult.mOwningPackageName);
+                boolean primaryOrSplit = searchResult.mOutcome == DEX_SEARCH_FOUND_PRIMARY ||
+                        searchResult.mOutcome == DEX_SEARCH_FOUND_SPLIT;
+
+                if (primaryOrSplit && !isUsedByOtherApps) {
+                    // If the dex file is the primary apk (or a split) and not isUsedByOtherApps
+                    // do not record it. This case does not bring any new usable information
+                    // and can be safely skipped.
+                    continue;
+                }
+
+                // Record dex file usage. If the current usage is a new pattern (e.g. new secondary,
+                // or UsedBytOtherApps), record will return true and we trigger an async write
+                // to disk to make sure we don't loose the data in case of a reboot.
+                if (mPackageDexUsage.record(searchResult.mOwningPackageName,
+                        dexPath, loaderUserId, loaderIsa, isUsedByOtherApps, primaryOrSplit)) {
+                    mPackageDexUsage.maybeWriteAsync();
+                }
+            } else {
+                // This can happen in a few situations:
+                // - bogus dex loads
+                // - recent installs/uninstalls that we didn't detect.
+                // - new installed splits
+                // If we can't find the owner of the dex we simply do not track it. The impact is
+                // that the dex file will not be considered for offline optimizations.
+                // TODO(calin): add hooks for install/uninstall notifications to
+                // capture new or obsolete packages.
+                if (DEBUG) {
+                    Slog.i(TAG, "Could not find owning package for dex file: " + dexPath);
+                }
+            }
+        }
+    }
+
+    /**
+     * Read the dex usage from disk and populate the code cache locations.
+     * @param existingPackages a map containing information about what packages
+     *          are available to what users. Only packages in this list will be
+     *          recognized during notifyDexLoad().
+     */
+    public void load(Map<Integer, List<PackageInfo>> existingPackages) {
+        try {
+            loadInternal(existingPackages);
+        } catch (Exception e) {
+            mPackageDexUsage.clear();
+            Slog.w(TAG, "Exception while loading package dex usage. " +
+                    "Starting with a fresh state.", e);
+        }
+    }
+
+    private void loadInternal(Map<Integer, List<PackageInfo>> existingPackages) {
+        Map<String, Set<Integer>> packageToUsersMap = new HashMap<>();
+        // Cache the code locations for the installed packages. This allows for
+        // faster lookups (no locks) when finding what package owns the dex file.
+        for (Map.Entry<Integer, List<PackageInfo>> entry : existingPackages.entrySet()) {
+            List<PackageInfo> packageInfoList = entry.getValue();
+            int userId = entry.getKey();
+            for (PackageInfo pi : packageInfoList) {
+                // Cache the code locations.
+                PackageCodeLocations pcl = mPackageCodeLocationsCache.get(pi.packageName);
+                if (pcl != null) {
+                    pcl.mergeAppDataDirs(pi.applicationInfo, userId);
+                } else {
+                    mPackageCodeLocationsCache.put(pi.packageName,
+                        new PackageCodeLocations(pi.applicationInfo, userId));
+                }
+                // Cache a map from package name to the set of user ids who installed the package.
+                // We will use it to sync the data and remove obsolete entries from
+                // mPackageDexUsage.
+                Set<Integer> users = putIfAbsent(
+                        packageToUsersMap, pi.packageName, new HashSet<>());
+                users.add(userId);
+            }
+        }
+
+        mPackageDexUsage.read();
+        mPackageDexUsage.syncData(packageToUsersMap);
+    }
+
+    /**
+     * Get the package dex usage for the given package name.
+     * @return the package data or null if there is no data available for this package.
+     */
+    public PackageDexUsage.PackageUseInfo getPackageUseInfo(String packageName) {
+        return mPackageDexUsage.getPackageUseInfo(packageName);
+    }
+
+    /**
+     * Retrieves the package which owns the given dexPath.
+     */
+    private DexSearchResult getDexPackage(
+            ApplicationInfo loadingAppInfo, String dexPath, int userId) {
+        // Ignore framework code.
+        // TODO(calin): is there a better way to detect it?
+        if (dexPath.startsWith("/system/framework/")) {
+            new DexSearchResult("framework", DEX_SEARCH_NOT_FOUND);
+        }
+
+        // First, check if the package which loads the dex file actually owns it.
+        // Most of the time this will be true and we can return early.
+        PackageCodeLocations loadingPackageCodeLocations =
+                new PackageCodeLocations(loadingAppInfo, userId);
+        int outcome = loadingPackageCodeLocations.searchDex(dexPath, userId);
+        if (outcome != DEX_SEARCH_NOT_FOUND) {
+            // TODO(calin): evaluate if we bother to detect symlinks at the dexPath level.
+            return new DexSearchResult(loadingPackageCodeLocations.mPackageName, outcome);
+        }
+
+        // The loadingPackage does not own the dex file.
+        // Perform a reverse look-up in the cache to detect if any package has ownership.
+        // Note that we can have false negatives if the cache falls out of date.
+        for (PackageCodeLocations pcl : mPackageCodeLocationsCache.values()) {
+            outcome = pcl.searchDex(dexPath, userId);
+            if (outcome != DEX_SEARCH_NOT_FOUND) {
+                return new DexSearchResult(pcl.mPackageName, outcome);
+            }
+        }
+
+        // Cache miss. Return not found for the moment.
+        //
+        // TODO(calin): this may be because of a newly installed package, an update
+        // or a new added user. We can either perform a full look up again or register
+        // observers to be notified of package/user updates.
+        return new DexSearchResult(null, DEX_SEARCH_NOT_FOUND);
+    }
+
+    private static <K,V> V putIfAbsent(Map<K,V> map, K key, V newValue) {
+        V existingValue = map.putIfAbsent(key, newValue);
+        return existingValue == null ? newValue : existingValue;
+    }
+
+    /**
+     * Convenience class to store the different locations where a package might
+     * own code.
+     */
+    private static class PackageCodeLocations {
+        private final String mPackageName;
+        private final String mBaseCodePath;
+        private final Set<String> mSplitCodePaths;
+        // Maps user id to the application private directory.
+        private final Map<Integer, Set<String>> mAppDataDirs;
+
+        public PackageCodeLocations(ApplicationInfo ai, int userId) {
+            mPackageName = ai.packageName;
+            mBaseCodePath = ai.sourceDir;
+            mSplitCodePaths = new HashSet<>();
+            if (ai.splitSourceDirs != null) {
+                for (String split : ai.splitSourceDirs) {
+                    mSplitCodePaths.add(split);
+                }
+            }
+            mAppDataDirs = new HashMap<>();
+            mergeAppDataDirs(ai, userId);
+        }
+
+        public void mergeAppDataDirs(ApplicationInfo ai, int userId) {
+            Set<String> dataDirs = putIfAbsent(mAppDataDirs, userId, new HashSet<>());
+            dataDirs.add(ai.dataDir);
+        }
+
+        public int searchDex(String dexPath, int userId) {
+            // First check that this package is installed or active for the given user.
+            // If we don't have a data dir it means this user is trying to load something
+            // unavailable for them.
+            Set<String> userDataDirs = mAppDataDirs.get(userId);
+            if (userDataDirs == null) {
+                Slog.w(TAG, "Trying to load a dex path which does not exist for the current " +
+                        "user. dexPath=" + dexPath + ", userId=" + userId);
+                return DEX_SEARCH_NOT_FOUND;
+            }
+
+            if (mBaseCodePath.equals(dexPath)) {
+                return DEX_SEARCH_FOUND_PRIMARY;
+            }
+            if (mSplitCodePaths.contains(dexPath)) {
+                return DEX_SEARCH_FOUND_SPLIT;
+            }
+            for (String dataDir : userDataDirs) {
+                if (dexPath.startsWith(dataDir)) {
+                    return DEX_SEARCH_FOUND_SECONDARY;
+                }
+            }
+
+            // TODO(calin): What if we get a symlink? e.g. data dir may be a symlink,
+            // /data/data/ -> /data/user/0/.
+            if (DEBUG) {
+                try {
+                    String dexPathReal = PackageManagerServiceUtils.realpath(new File(dexPath));
+                    if (dexPathReal != dexPath) {
+                        Slog.d(TAG, "Dex loaded with symlink. dexPath=" +
+                                dexPath + " dexPathReal=" + dexPathReal);
+                    }
+                } catch (IOException e) {
+                    // Ignore
+                }
+            }
+            return DEX_SEARCH_NOT_FOUND;
+        }
+    }
+
+    /**
+     * Convenience class to store ownership search results.
+     */
+    private class DexSearchResult {
+        private String mOwningPackageName;
+        private int mOutcome;
+
+        public DexSearchResult(String owningPackageName, int outcome) {
+            this.mOwningPackageName = owningPackageName;
+            this.mOutcome = outcome;
+        }
+
+        @Override
+        public String toString() {
+            return mOwningPackageName + "-" + mOutcome;
+        }
+    }
+
+
+}
diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
new file mode 100644
index 0000000..10384a2
--- /dev/null
+++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
@@ -0,0 +1,512 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.pm.dex;
+
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.os.Build;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.FastPrintWriter;
+import com.android.server.pm.AbstractStatsBase;
+import com.android.server.pm.PackageManagerServiceUtils;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Iterator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import dalvik.system.VMRuntime;
+import libcore.io.IoUtils;
+
+/**
+ * Stat file which store usage information about dex files.
+ */
+public class PackageDexUsage extends AbstractStatsBase<Void> {
+    private final static String TAG = "PackageDexUsage";
+
+    private final static int PACKAGE_DEX_USAGE_VERSION = 1;
+    private final static String PACKAGE_DEX_USAGE_VERSION_HEADER =
+            "PACKAGE_MANAGER__PACKAGE_DEX_USAGE__";
+
+    private final static String SPLIT_CHAR = ",";
+    private final static String DEX_LINE_CHAR = "#";
+
+    // Map which structures the information we have on a package.
+    // Maps package name to package data (which stores info about UsedByOtherApps and
+    // secondary dex files.).
+    // Access to this map needs synchronized.
+    @GuardedBy("mPackageUseInfoMap")
+    private Map<String, PackageUseInfo> mPackageUseInfoMap;
+
+    public PackageDexUsage() {
+        super("package-dex-usage.list", "PackageDexUsage_DiskWriter", /*lock*/ false);
+        mPackageUseInfoMap = new HashMap<>();
+    }
+
+    /**
+     * Record a dex file load.
+     *
+     * Note this is called when apps load dex files and as such it should return
+     * as fast as possible.
+     *
+     * @param loadingPackage the package performing the load
+     * @param dexPath the path of the dex files being loaded
+     * @param ownerUserId the user id which runs the code loading the dex files
+     * @param loaderIsa the ISA of the app loading the dex files
+     * @param isUsedByOtherApps whether or not this dex file was not loaded by its owning package
+     * @param primaryOrSplit whether or not the dex file is a primary/split dex. True indicates
+     *        the file is either primary or a split. False indicates the file is secondary dex.
+     * @return true if the dex load constitutes new information, or false if this information
+     *         has been seen before.
+     */
+    public boolean record(String owningPackageName, String dexPath, int ownerUserId,
+            String loaderIsa, boolean isUsedByOtherApps, boolean primaryOrSplit) {
+        if (!PackageManagerServiceUtils.checkISA(loaderIsa)) {
+            throw new IllegalArgumentException("loaderIsa " + loaderIsa + " is unsupported");
+        }
+        synchronized (mPackageUseInfoMap) {
+            PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(owningPackageName);
+            if (packageUseInfo == null) {
+                // This is the first time we see the package.
+                packageUseInfo = new PackageUseInfo();
+                if (primaryOrSplit) {
+                    // If we have a primary or a split apk, set isUsedByOtherApps.
+                    // We do not need to record the loaderIsa or the owner because we compile
+                    // primaries for all users and all ISAs.
+                    packageUseInfo.mIsUsedByOtherApps = isUsedByOtherApps;
+                } else {
+                    // For secondary dex files record the loaderISA and the owner. We'll need
+                    // to know under which user to compile and for what ISA.
+                    packageUseInfo.mDexUseInfoMap.put(
+                            dexPath, new DexUseInfo(isUsedByOtherApps, ownerUserId, loaderIsa));
+                }
+                mPackageUseInfoMap.put(owningPackageName, packageUseInfo);
+                return true;
+            } else {
+                // We already have data on this package. Amend it.
+                if (primaryOrSplit) {
+                    // We have a possible update on the primary apk usage. Merge
+                    // isUsedByOtherApps information and return if there was an update.
+                    return packageUseInfo.merge(isUsedByOtherApps);
+                } else {
+                    DexUseInfo newData = new DexUseInfo(
+                            isUsedByOtherApps, ownerUserId, loaderIsa);
+                    DexUseInfo existingData = packageUseInfo.mDexUseInfoMap.get(dexPath);
+                    if (existingData == null) {
+                        // It's the first time we see this dex file.
+                        packageUseInfo.mDexUseInfoMap.put(dexPath, newData);
+                        return true;
+                    } else {
+                        if (ownerUserId != existingData.mOwnerUserId) {
+                            // Oups, this should never happen, the DexManager who calls this should
+                            // do the proper checks and not call record if the user does not own the
+                            // dex path.
+                            // Secondary dex files are stored in the app user directory. A change in
+                            // owningUser for the same path means that something went wrong at some
+                            // higher level, and the loaderUser was allowed to cross
+                            // user-boundaries and access data from what we know to be the owner
+                            // user.
+                            throw new IllegalArgumentException("Trying to change ownerUserId for "
+                                    + " dex path " + dexPath + " from " + existingData.mOwnerUserId
+                                    + " to " + ownerUserId);
+                        }
+                        // Merge the information into the existing data.
+                        // Returns true if there was an update.
+                        return existingData.merge(newData);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Convenience method for sync reads which does not force the user to pass a useless
+     * (Void) null.
+     */
+    public void read() {
+      read((Void) null);
+    }
+
+    /**
+     * Convenience method for async writes which does not force the user to pass a useless
+     * (Void) null.
+     */
+    public void maybeWriteAsync() {
+      maybeWriteAsync((Void) null);
+    }
+
+    @Override
+    protected void writeInternal(Void data) {
+        AtomicFile file = getFile();
+        FileOutputStream f = null;
+
+        try {
+            f = file.startWrite();
+            OutputStreamWriter osw = new OutputStreamWriter(f);
+            write(osw);
+            osw.flush();
+            file.finishWrite(f);
+        } catch (IOException e) {
+            if (f != null) {
+                file.failWrite(f);
+            }
+            Slog.e(TAG, "Failed to write usage for dex files", e);
+        }
+    }
+
+    /**
+     * File format:
+     *
+     * file_magic_version
+     * package_name_1
+     * #dex_file_path_1_1
+     * user_1_1, used_by_other_app_1_1, user_isa_1_1_1, user_isa_1_1_2
+     * #dex_file_path_1_2
+     * user_1_2, used_by_other_app_1_2, user_isa_1_2_1, user_isa_1_2_2
+     * ...
+     * package_name_2
+     * #dex_file_path_2_1
+     * user_2_1, used_by_other_app_2_1, user_isa_2_1_1, user_isa_2_1_2
+     * #dex_file_path_2_2,
+     * user_2_2, used_by_other_app_2_2, user_isa_2_2_1, user_isa_2_2_2
+     * ...
+    */
+    /* package */ void write(Writer out) {
+        // Make a clone to avoid locking while writing to disk.
+        Map<String, PackageUseInfo> packageUseInfoMapClone = clonePackageUseInfoMap();
+
+        FastPrintWriter fpw = new FastPrintWriter(out);
+
+        // Write the header.
+        fpw.print(PACKAGE_DEX_USAGE_VERSION_HEADER);
+        fpw.println(PACKAGE_DEX_USAGE_VERSION);
+
+        for (Map.Entry<String, PackageUseInfo> pEntry : packageUseInfoMapClone.entrySet()) {
+            // Write the package line.
+            String packageName = pEntry.getKey();
+            PackageUseInfo packageUseInfo = pEntry.getValue();
+
+            fpw.println(String.join(SPLIT_CHAR, packageName,
+                    writeBoolean(packageUseInfo.mIsUsedByOtherApps)));
+
+            // Write dex file lines.
+            for (Map.Entry<String, DexUseInfo> dEntry : packageUseInfo.mDexUseInfoMap.entrySet()) {
+                String dexPath = dEntry.getKey();
+                DexUseInfo dexUseInfo = dEntry.getValue();
+                fpw.println(DEX_LINE_CHAR + dexPath);
+                fpw.print(String.join(SPLIT_CHAR, Integer.toString(dexUseInfo.mOwnerUserId),
+                        writeBoolean(dexUseInfo.mIsUsedByOtherApps)));
+                for (String isa : dexUseInfo.mLoaderIsas) {
+                    fpw.print(SPLIT_CHAR + isa);
+                }
+                fpw.println();
+            }
+        }
+        fpw.flush();
+    }
+
+    @Override
+    protected void readInternal(Void data) {
+        AtomicFile file = getFile();
+        BufferedReader in = null;
+        try {
+            in = new BufferedReader(new InputStreamReader(file.openRead()));
+            read(in);
+        } catch (FileNotFoundException expected) {
+            // The file may not be there. E.g. When we first take the OTA with this feature.
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed to parse package dex usage.", e);
+        } finally {
+            IoUtils.closeQuietly(in);
+        }
+    }
+
+    /* package */ void read(Reader reader) throws IOException {
+        Map<String, PackageUseInfo> data = new HashMap<>();
+        BufferedReader in = new BufferedReader(reader);
+        // Read header, do version check.
+        String versionLine = in.readLine();
+        if (versionLine == null) {
+            throw new IllegalStateException("No version line found.");
+        } else {
+            if (!versionLine.startsWith(PACKAGE_DEX_USAGE_VERSION_HEADER)) {
+                // TODO(calin): the caller is responsible to clear the file.
+                throw new IllegalStateException("Invalid version line: " + versionLine);
+            }
+            int version = Integer.parseInt(
+                    versionLine.substring(PACKAGE_DEX_USAGE_VERSION_HEADER.length()));
+            if (version != PACKAGE_DEX_USAGE_VERSION) {
+                throw new IllegalStateException("Unexpected version: " + version);
+            }
+        }
+
+        String s = null;
+        String currentPakage = null;
+        PackageUseInfo currentPakageData = null;
+
+        Set<String> supportedIsas = new HashSet<>();
+        for (String abi : Build.SUPPORTED_ABIS) {
+            supportedIsas.add(VMRuntime.getInstructionSet(abi));
+        }
+        while ((s = in.readLine()) != null) {
+            if (s.startsWith(DEX_LINE_CHAR)) {
+                // This is the start of the the dex lines.
+                // We expect two lines for each dex entry:
+                // #dexPaths
+                // onwerUserId,isUsedByOtherApps,isa1,isa2
+                if (currentPakage == null) {
+                    throw new IllegalStateException(
+                        "Malformed PackageDexUsage file. Expected package line before dex line.");
+                }
+
+                // First line is the dex path.
+                String dexPath = s.substring(DEX_LINE_CHAR.length());
+                // Next line is the dex data.
+                s = in.readLine();
+                if (s == null) {
+                    throw new IllegalStateException("Could not fine dexUseInfo for line: " + s);
+                }
+
+                // We expect at least 3 elements (isUsedByOtherApps, userId, isa).
+                String[] elems = s.split(SPLIT_CHAR);
+                if (elems.length < 3) {
+                    throw new IllegalStateException("Invalid PackageDexUsage line: " + s);
+                }
+                int ownerUserId = Integer.parseInt(elems[0]);
+                boolean isUsedByOtherApps = readBoolean(elems[1]);
+                DexUseInfo dexUseInfo = new DexUseInfo(isUsedByOtherApps, ownerUserId);
+                for (int i = 2; i < elems.length; i++) {
+                    String isa = elems[i];
+                    if (supportedIsas.contains(isa)) {
+                        dexUseInfo.mLoaderIsas.add(elems[i]);
+                    } else {
+                        // Should never happen unless someone crafts the file manually.
+                        // In theory it could if we drop a supported ISA after an OTA but we don't
+                        // do that.
+                        Slog.wtf(TAG, "Unsupported ISA when parsing PackageDexUsage: " + isa);
+                    }
+                }
+                if (supportedIsas.isEmpty()) {
+                    Slog.wtf(TAG, "Ignore dexPath when parsing PackageDexUsage because of " +
+                            "unsupported isas. dexPath=" + dexPath);
+                    continue;
+                }
+                currentPakageData.mDexUseInfoMap.put(dexPath, dexUseInfo);
+            } else {
+                // This is a package line.
+                // We expect it to be: `packageName,isUsedByOtherApps`.
+                String[] elems = s.split(SPLIT_CHAR);
+                if (elems.length != 2) {
+                    throw new IllegalStateException("Invalid PackageDexUsage line: " + s);
+                }
+                currentPakage = elems[0];
+                currentPakageData = new PackageUseInfo();
+                currentPakageData.mIsUsedByOtherApps = readBoolean(elems[1]);
+                data.put(currentPakage, currentPakageData);
+            }
+        }
+
+        synchronized (mPackageUseInfoMap) {
+            mPackageUseInfoMap.clear();
+            mPackageUseInfoMap.putAll(data);
+        }
+    }
+
+    /**
+     * Syncs the existing data with the set of available packages by removing obsolete entries.
+     */
+    public void syncData(Map<String, Set<Integer>> packageToUsersMap) {
+        synchronized (mPackageUseInfoMap) {
+            Iterator<Map.Entry<String, PackageUseInfo>> pIt =
+                    mPackageUseInfoMap.entrySet().iterator();
+            while (pIt.hasNext()) {
+                Map.Entry<String, PackageUseInfo> pEntry = pIt.next();
+                String packageName = pEntry.getKey();
+                PackageUseInfo packageUseInfo = pEntry.getValue();
+                Set<Integer> users = packageToUsersMap.get(packageName);
+                if (users == null) {
+                    // The package doesn't exist anymore, remove the record.
+                    pIt.remove();
+                } else {
+                    // The package exists but we can prune the entries associated with non existing
+                    // users.
+                    Iterator<Map.Entry<String, DexUseInfo>> dIt =
+                            packageUseInfo.mDexUseInfoMap.entrySet().iterator();
+                    while (dIt.hasNext()) {
+                        DexUseInfo dexUseInfo = dIt.next().getValue();
+                        if (!users.contains(dexUseInfo.mOwnerUserId)) {
+                            // User was probably removed. Delete its dex usage info.
+                            dIt.remove();
+                        }
+                    }
+                    if (!packageUseInfo.mIsUsedByOtherApps
+                            && packageUseInfo.mDexUseInfoMap.isEmpty()) {
+                        // The package is not used by other apps and we removed all its dex files
+                        // records. Remove the entire package record as well.
+                        pIt.remove();
+                    }
+                }
+            }
+        }
+    }
+
+    public PackageUseInfo getPackageUseInfo(String packageName) {
+        synchronized (mPackageUseInfoMap) {
+            return mPackageUseInfoMap.get(packageName);
+        }
+    }
+
+    public void clear() {
+        synchronized (mPackageUseInfoMap) {
+            mPackageUseInfoMap.clear();
+        }
+    }
+    // Creates a deep copy of the class' mPackageUseInfoMap.
+    private Map<String, PackageUseInfo> clonePackageUseInfoMap() {
+        Map<String, PackageUseInfo> clone = new HashMap<>();
+        synchronized (mPackageUseInfoMap) {
+            for (Map.Entry<String, PackageUseInfo> e : mPackageUseInfoMap.entrySet()) {
+                clone.put(e.getKey(), new PackageUseInfo(e.getValue()));
+            }
+        }
+        return clone;
+    }
+
+    private String writeBoolean(boolean bool) {
+        return bool ? "1" : "0";
+    }
+
+    private boolean readBoolean(String bool) {
+        if ("0".equals(bool)) return false;
+        if ("1".equals(bool)) return true;
+        throw new IllegalArgumentException("Unknown bool encoding: " + bool);
+    }
+
+    private boolean contains(int[] array, int elem) {
+        for (int i = 0; i < array.length; i++) {
+            if (elem == array[i]) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public String dump() {
+        StringWriter sw = new StringWriter();
+        write(sw);
+        return sw.toString();
+    }
+
+    /**
+     * Stores data on how a package and its dex files are used.
+     */
+    public static class PackageUseInfo {
+        // This flag is for the primary and split apks. It is set to true whenever one of them
+        // is loaded by another app.
+        private boolean mIsUsedByOtherApps;
+        // Map dex paths to their data (isUsedByOtherApps, owner id, loader isa).
+        private final Map<String, DexUseInfo> mDexUseInfoMap;
+
+        public PackageUseInfo() {
+            mIsUsedByOtherApps = false;
+            mDexUseInfoMap = new HashMap<>();
+        }
+
+        // Creates a deep copy of the `other`.
+        public PackageUseInfo(PackageUseInfo other) {
+            mIsUsedByOtherApps = other.mIsUsedByOtherApps;
+            mDexUseInfoMap = new HashMap<>();
+            for (Map.Entry<String, DexUseInfo> e : other.mDexUseInfoMap.entrySet()) {
+                mDexUseInfoMap.put(e.getKey(), new DexUseInfo(e.getValue()));
+            }
+        }
+
+        private boolean merge(boolean isUsedByOtherApps) {
+            boolean oldIsUsedByOtherApps = mIsUsedByOtherApps;
+            mIsUsedByOtherApps = mIsUsedByOtherApps || isUsedByOtherApps;
+            return oldIsUsedByOtherApps != this.mIsUsedByOtherApps;
+        }
+
+        public boolean isUsedByOtherApps() {
+            return mIsUsedByOtherApps;
+        }
+
+        public Map<String, DexUseInfo> getDexUseInfoMap() {
+            return mDexUseInfoMap;
+        }
+    }
+
+    /**
+     * Stores data about a loaded dex files.
+     */
+    public static class DexUseInfo {
+        private boolean mIsUsedByOtherApps;
+        private final int mOwnerUserId;
+        private final Set<String> mLoaderIsas;
+
+        public DexUseInfo(boolean isUsedByOtherApps, int ownerUserId) {
+            this(isUsedByOtherApps, ownerUserId, null);
+        }
+
+        public DexUseInfo(boolean isUsedByOtherApps, int ownerUserId, String loaderIsa) {
+            mIsUsedByOtherApps = isUsedByOtherApps;
+            mOwnerUserId = ownerUserId;
+            mLoaderIsas = new HashSet<>();
+            if (loaderIsa != null) {
+                mLoaderIsas.add(loaderIsa);
+            }
+        }
+
+        // Creates a deep copy of the `other`.
+        public DexUseInfo(DexUseInfo other) {
+            mIsUsedByOtherApps = other.mIsUsedByOtherApps;
+            mOwnerUserId = other.mOwnerUserId;
+            mLoaderIsas = new HashSet<>(other.mLoaderIsas);
+        }
+
+        private boolean merge(DexUseInfo dexUseInfo) {
+            boolean oldIsUsedByOtherApps = mIsUsedByOtherApps;
+            mIsUsedByOtherApps = mIsUsedByOtherApps || dexUseInfo.mIsUsedByOtherApps;
+            boolean updateIsas = mLoaderIsas.addAll(dexUseInfo.mLoaderIsas);
+            return updateIsas || (oldIsUsedByOtherApps != mIsUsedByOtherApps);
+        }
+
+        public boolean isUsedByOtherApps() {
+            return mIsUsedByOtherApps;
+        }
+
+        public int getOwnerUserId() {
+            return mOwnerUserId;
+        }
+
+        public Set<String> getLoaderIsas() {
+            return mLoaderIsas;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java b/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
index b260e4e..b704eb1 100644
--- a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
@@ -20,7 +20,7 @@
 
 import java.io.File;
 import java.io.IOException;
-import libcore.tzdata.update.TzDataBundleInstaller;
+import libcore.tzdata.update2.TimeZoneBundleInstaller;
 
 /**
  * An install receiver responsible for installing timezone data updates.
@@ -29,18 +29,19 @@
 
     private static final String TAG = "TZDataInstallReceiver";
 
+    private static final File SYSTEM_TZ_DATA_FILE = new File("/system/usr/share/zoneinfo/tzdata");
     private static final File TZ_DATA_DIR = new File("/data/misc/zoneinfo");
     private static final String UPDATE_DIR_NAME = TZ_DATA_DIR.getPath() + "/updates/";
     private static final String UPDATE_METADATA_DIR_NAME = "metadata/";
     private static final String UPDATE_VERSION_FILE_NAME = "version";
     private static final String UPDATE_CONTENT_FILE_NAME = "tzdata_bundle.zip";
 
-    private final TzDataBundleInstaller installer;
+    private final TimeZoneBundleInstaller installer;
 
     public TzDataInstallReceiver() {
         super(UPDATE_DIR_NAME, UPDATE_CONTENT_FILE_NAME, UPDATE_METADATA_DIR_NAME,
                 UPDATE_VERSION_FILE_NAME);
-        installer = new TzDataBundleInstaller(TAG, TZ_DATA_DIR);
+        installer = new TimeZoneBundleInstaller(TAG, SYSTEM_TZ_DATA_FILE, TZ_DATA_DIR);
     }
 
     @Override
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index ecdc71e..531f946 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -17,30 +17,30 @@
 #define LOG_TAG "BatteryStatsService"
 //#define LOG_NDEBUG 0
 
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <semaphore.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
 #include <android_runtime/AndroidRuntime.h>
 #include <jni.h>
 
 #include <ScopedLocalRef.h>
 #include <ScopedPrimitiveArray.h>
 
-#include <cutils/log.h>
+#include <log/log.h>
 #include <utils/misc.h>
 #include <utils/Log.h>
 #include <hardware/hardware.h>
 #include <hardware/power.h>
 #include <suspend/autosuspend.h>
 
-#include <inttypes.h>
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <semaphore.h>
-#include <stddef.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
 namespace android
 {
 
diff --git a/services/core/jni/com_android_server_connectivity_Vpn.cpp b/services/core/jni/com_android_server_connectivity_Vpn.cpp
index c54d732..4d85d9a 100644
--- a/services/core/jni/com_android_server_connectivity_Vpn.cpp
+++ b/services/core/jni/com_android_server_connectivity_Vpn.cpp
@@ -17,24 +17,25 @@
 #define LOG_NDEBUG 0
 
 #define LOG_TAG "VpnJni"
-#include <cutils/log.h>
-#include "netutils/ifc.h"
 
-#include <stdio.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
 #include <arpa/inet.h>
 #include <errno.h>
 #include <fcntl.h>
-
 #include <linux/if.h>
 #include <linux/if_tun.h>
 #include <linux/route.h>
 #include <linux/ipv6_route.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <log/log.h>
+
+#include "netutils/ifc.h"
 
 #include "jni.h"
 #include "JNIHelp.h"
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 2187c57..336351e 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_CERTIFICATE := platform
 
 # These are not normally accessible from apps so they must be explicitly included.
-LOCAL_JNI_SHARED_LIBRARIES := libservicestestsjni \
+LOCAL_JNI_SHARED_LIBRARIES := \
     libbacktrace \
     libbase \
     libbinder \
@@ -47,36 +47,3 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 include $(BUILD_PACKAGE)
-
-#########################################################################
-# Build JNI Shared Library
-#########################################################################
-
-LOCAL_PATH:= $(LOCAL_PATH)/jni
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := -Wall -Wextra -Werror
-
-LOCAL_C_INCLUDES := \
-  libpcap \
-  hardware/google/apf
-
-LOCAL_SRC_FILES := $(call all-cpp-files-under)
-
-LOCAL_SHARED_LIBRARIES := \
-  libbinder \
-  liblog \
-  libcutils \
-  libnativehelper \
-  libnetdaidl
-
-LOCAL_STATIC_LIBRARIES := \
-  libpcap \
-  libapf
-
-LOCAL_MODULE := libservicestestsjni
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 69d27f2..1189dae 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -23,6 +23,7 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.Assert.fail;
 
@@ -53,6 +54,7 @@
 import android.net.INetworkRecommendationProvider;
 import android.net.INetworkScoreCache;
 import android.net.NetworkKey;
+import android.net.NetworkScoreManager;
 import android.net.NetworkScorerAppManager;
 import android.net.NetworkScorerAppManager.NetworkScorerAppData;
 import android.net.RecommendationRequest;
@@ -60,6 +62,7 @@
 import android.net.ScoredNetwork;
 import android.net.WifiKey;
 import android.net.wifi.WifiConfiguration;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
@@ -134,9 +137,10 @@
 
         mNetworkScoreService.systemRunning();
 
-        verify(mContext).bindServiceAsUser(MockUtils.checkIntent(new Intent().setComponent(
-                new ComponentName(NEW_SCORER.packageName,
-                    NEW_SCORER.recommendationServiceClassName))),
+        verify(mContext).bindServiceAsUser(MockUtils.checkIntent(
+                new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS)
+                        .setComponent(new ComponentName(NEW_SCORER.packageName,
+                                NEW_SCORER.recommendationServiceClassName))),
                 any(ServiceConnection.class),
                 eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
                 eq(UserHandle.SYSTEM));
@@ -145,11 +149,11 @@
     @Test
     public void testRequestScores_noPermission() throws Exception {
         doThrow(new SecurityException()).when(mContext)
-            .enforceCallingOrSelfPermission(eq(permission.BROADCAST_NETWORK_PRIVILEGED),
+            .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES),
                 anyString());
         try {
             mNetworkScoreService.requestScores(null);
-            fail("BROADCAST_NETWORK_PRIVILEGED not enforced.");
+            fail("REQUEST_NETWORK_SCORES not enforced.");
         } catch (SecurityException e) {
             // expected
         }
@@ -182,11 +186,11 @@
     @Test
     public void testRequestRecommendation_noPermission() throws Exception {
         doThrow(new SecurityException()).when(mContext)
-            .enforceCallingOrSelfPermission(eq(permission.BROADCAST_NETWORK_PRIVILEGED),
+            .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES),
                 anyString());
         try {
             mNetworkScoreService.requestRecommendation(mRecommendationRequest);
-            fail("BROADCAST_NETWORK_PRIVILEGED not enforced.");
+            fail("REQUEST_NETWORK_SCORES not enforced.");
         } catch (SecurityException e) {
             // expected
         }
@@ -259,7 +263,7 @@
 
     @Test
     public void testUpdateScores_notActiveScorer() {
-        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
+        bindToScorer(false /*callerIsScorer*/);
 
         try {
             mNetworkScoreService.updateScores(new ScoredNetwork[0]);
@@ -271,7 +275,7 @@
 
     @Test
     public void testUpdateScores_oneRegisteredCache() throws RemoteException {
-        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
+        bindToScorer(true /*callerIsScorer*/);
 
         mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
                 mNetworkScoreCache, CACHE_FILTER_NONE);
@@ -286,7 +290,7 @@
 
     @Test
     public void testUpdateScores_twoRegisteredCaches() throws RemoteException {
-        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
+        bindToScorer(true /*callerIsScorer*/);
 
         mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
                 mNetworkScoreCache, CACHE_FILTER_NONE);
@@ -320,9 +324,9 @@
     }
 
     @Test
-    public void testClearScores_notActiveScorer_noBroadcastNetworkPermission() {
-        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
-        when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+    public void testClearScores_notActiveScorer_noRequestNetworkScoresPermission() {
+        bindToScorer(false /*callerIsScorer*/);
+        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
             .thenReturn(PackageManager.PERMISSION_DENIED);
         try {
             mNetworkScoreService.clearScores();
@@ -333,9 +337,9 @@
     }
 
     @Test
-    public void testClearScores_activeScorer_noBroadcastNetworkPermission() {
-        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
-        when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+    public void testClearScores_activeScorer_noRequestNetworkScoresPermission() {
+        bindToScorer(true /*callerIsScorer*/);
+        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
             .thenReturn(PackageManager.PERMISSION_DENIED);
 
         mNetworkScoreService.clearScores();
@@ -343,7 +347,7 @@
 
     @Test
     public void testClearScores_activeScorer() throws RemoteException {
-        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
+        bindToScorer(true /*callerIsScorer*/);
 
         mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
                 CACHE_FILTER_NONE);
@@ -353,10 +357,10 @@
     }
 
     @Test
-    public void testClearScores_notActiveScorer_hasBroadcastNetworkPermission()
+    public void testClearScores_notActiveScorer_hasRequestNetworkScoresPermission()
             throws RemoteException {
-        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
-        when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+        bindToScorer(false /*callerIsScorer*/);
+        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
                 .thenReturn(PackageManager.PERMISSION_GRANTED);
 
         mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
@@ -380,9 +384,9 @@
     }
 
     @Test
-    public void testDisableScoring_notActiveScorer_noBroadcastNetworkPermission() {
-        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
-        when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+    public void testDisableScoring_notActiveScorer_noRequestNetworkScoresPermission() {
+        bindToScorer(false /*callerIsScorer*/);
+        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
                 .thenReturn(PackageManager.PERMISSION_DENIED);
 
         try {
@@ -394,9 +398,9 @@
     }
 
     @Test
-    public void testRegisterNetworkScoreCache_noBroadcastNetworkPermission() {
+    public void testRegisterNetworkScoreCache_noRequestNetworkScoresPermission() {
         doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
-                eq(permission.BROADCAST_NETWORK_PRIVILEGED), anyString());
+                eq(permission.REQUEST_NETWORK_SCORES), anyString());
 
         try {
             mNetworkScoreService.registerNetworkScoreCache(
@@ -408,9 +412,9 @@
     }
 
     @Test
-    public void testUnregisterNetworkScoreCache_noBroadcastNetworkPermission() {
+    public void testUnregisterNetworkScoreCache_noRequestNetworkScoresPermission() {
         doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
-                eq(permission.BROADCAST_NETWORK_PRIVILEGED), anyString());
+                eq(permission.REQUEST_NETWORK_SCORES), anyString());
 
         try {
             mNetworkScoreService.unregisterNetworkScoreCache(
@@ -446,6 +450,42 @@
         assertFalse(stringWriter.toString().isEmpty());
     }
 
+    @Test
+    public void testIsCallerActiveScorer_noBoundService() throws Exception {
+        mNetworkScoreService.systemRunning();
+
+        assertFalse(mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid()));
+    }
+
+    @Test
+    public void testIsCallerActiveScorer_boundServiceIsNotCaller() throws Exception {
+        bindToScorer(false /*callerIsScorer*/);
+
+        assertFalse(mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid()));
+    }
+
+    @Test
+    public void testIsCallerActiveScorer_boundServiceIsCaller() throws Exception {
+        bindToScorer(true /*callerIsScorer*/);
+
+        assertTrue(mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid()));
+    }
+
+    @Test
+    public void testGetActiveScorerPackage_notActive() throws Exception {
+        mNetworkScoreService.systemRunning();
+
+        assertNull(mNetworkScoreService.getActiveScorerPackage());
+    }
+
+    @Test
+    public void testGetActiveScorerPackage_active() throws Exception {
+        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
+        mNetworkScoreService.systemRunning();
+
+        assertEquals(NEW_SCORER.packageName, mNetworkScoreService.getActiveScorerPackage());
+    }
+
     // "injects" the mock INetworkRecommendationProvider into the NetworkScoreService.
     private void injectProvider() {
         final ComponentName componentName = new ComponentName(NEW_SCORER.packageName,
@@ -465,4 +505,14 @@
         });
         mNetworkScoreService.systemRunning();
     }
+
+    private void bindToScorer(boolean callerIsScorer) {
+        final int callingUid = callerIsScorer ? Binder.getCallingUid() : 0;
+        NetworkScorerAppData appData = new NetworkScorerAppData(NEW_SCORER.packageName,
+                callingUid, NEW_SCORER.recommendationServiceClassName);
+        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(appData);
+        when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(),
+                isA(UserHandle.class))).thenReturn(true);
+        mNetworkScoreService.systemRunning();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java
new file mode 100644
index 0000000..2a7cbc2
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageStats;
+import android.os.UserHandle;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.util.Arrays;
+
+public class InstallerTest extends AndroidTestCase {
+    private static final String TAG = "InstallerTest";
+
+    private Installer mInstaller;
+
+    @Override
+    public void setUp() throws Exception {
+        mInstaller = new Installer(getContext());
+        mInstaller.onStart();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mInstaller = null;
+    }
+
+    public void testGetAppSize() throws Exception {
+        final PackageManager pm = getContext().getPackageManager();
+        for (ApplicationInfo app : pm.getInstalledApplications(0)) {
+            final int userId = UserHandle.getUserId(app.uid);
+            final int appId = UserHandle.getAppId(app.uid);
+
+            final String[] packageNames = pm.getPackagesForUid(app.uid);
+            final long[] ceDataInodes = new long[packageNames.length];
+            final String[] codePaths = new String[packageNames.length];
+
+            for (int i = 0; i < packageNames.length; i++) {
+                final ApplicationInfo info = pm.getApplicationInfo(packageNames[i], 0);
+                codePaths[i] = info.getCodePath();
+            }
+
+            final PackageStats stats = new PackageStats(app.packageName);
+            final PackageStats quotaStats = new PackageStats(app.packageName);
+
+            mInstaller.getAppSize(app.volumeUuid, packageNames, userId, 0,
+                    appId, ceDataInodes, codePaths, stats);
+
+            mInstaller.getAppSize(app.volumeUuid, packageNames, userId, Installer.FLAG_USE_QUOTA,
+                    appId, ceDataInodes, codePaths, quotaStats);
+
+            checkEquals(Arrays.toString(packageNames) + " UID=" + app.uid, stats, quotaStats);
+        }
+    }
+
+    public void testGetUserSize() throws Exception {
+        int[] appIds = null;
+
+        final PackageManager pm = getContext().getPackageManager();
+        for (ApplicationInfo app : pm.getInstalledApplications(0)) {
+            final int appId = UserHandle.getAppId(app.uid);
+            if (!ArrayUtils.contains(appIds, appId)) {
+                appIds = ArrayUtils.appendInt(appIds, appId);
+            }
+        }
+
+        final PackageStats stats = new PackageStats("android");
+        final PackageStats quotaStats = new PackageStats("android");
+
+        mInstaller.getUserSize(null, UserHandle.USER_SYSTEM, 0,
+                appIds, stats);
+
+        mInstaller.getUserSize(null, UserHandle.USER_SYSTEM, Installer.FLAG_USE_QUOTA,
+                appIds, quotaStats);
+
+        checkEquals(Arrays.toString(appIds), stats, quotaStats);
+    }
+
+    public void testGetExternalSize() throws Exception {
+
+        final long[] stats = mInstaller.getExternalSize(null, UserHandle.USER_SYSTEM, 0);
+
+        final long[] quotaStats = mInstaller.getExternalSize(null, UserHandle.USER_SYSTEM,
+                Installer.FLAG_USE_QUOTA);
+
+        for (int i = 0; i < stats.length; i++) {
+            checkEquals("#" + i, stats[i], quotaStats[i]);
+        }
+    }
+
+    private static void checkEquals(String msg, PackageStats a, PackageStats b) {
+        checkEquals(msg + " codeSize", a.codeSize, b.codeSize);
+        checkEquals(msg + " dataSize", a.dataSize, b.dataSize);
+        checkEquals(msg + " cacheSize", a.cacheSize, b.cacheSize);
+        checkEquals(msg + " externalCodeSize", a.externalCodeSize, b.externalCodeSize);
+        checkEquals(msg + " externalDataSize", a.externalDataSize, b.externalDataSize);
+        checkEquals(msg + " externalCacheSize", a.externalCacheSize, b.externalCacheSize);
+    }
+
+    private static void checkEquals(String msg, long expected, long actual) {
+        if (expected != actual) {
+            Log.e(TAG, msg + " expected " + expected + " actual " + actual);
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
new file mode 100644
index 0000000..b655f3a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.pm.dex;
+
+import android.os.Build;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import dalvik.system.VMRuntime;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
+import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DexManagerTests {
+    private DexManager mDexManager;
+
+    private TestData mFooUser0;
+    private TestData mBarUser0;
+    private TestData mBarUser1;
+    private TestData mInvalidIsa;
+    private TestData mDoesNotExist;
+
+    private int mUser0;
+    private int mUser1;
+    @Before
+    public void setup() {
+
+        mUser0 = 0;
+        mUser1 = 1;
+
+        String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
+        String foo = "foo";
+        String bar = "bar";
+
+        mFooUser0 = new TestData(foo, isa, mUser0);
+        mBarUser0 = new TestData(bar, isa, mUser0);
+        mBarUser1 = new TestData(bar, isa, mUser1);
+        mInvalidIsa = new TestData("INVALID", "INVALID_ISA", mUser0);
+        mDoesNotExist = new TestData("DOES.NOT.EXIST", isa, mUser1);
+
+
+        mDexManager = new DexManager();
+
+        // Foo and Bar are available to user0.
+        // Only Bar is available to user1;
+        Map<Integer, List<PackageInfo>> existingPackages = new HashMap<>();
+        existingPackages.put(mUser0, Arrays.asList(mFooUser0.mPackageInfo, mBarUser0.mPackageInfo));
+        existingPackages.put(mUser1, Arrays.asList(mBarUser1.mPackageInfo));
+        mDexManager.load(existingPackages);
+    }
+
+    @Test
+    public void testNotifyPrimaryUse() {
+        // The main dex file and splits are re-loaded by the app.
+        notifyDexLoad(mFooUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0);
+
+        // Package is not used by others, so we should get nothing back.
+        assertNull(getPackageUseInfo(mFooUser0));
+    }
+
+    @Test
+    public void testNotifyPrimaryForeignUse() {
+        // Foo loads Bar main apks.
+        notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0);
+
+        // Bar is used by others now and should be in our records
+        PackageUseInfo pui = getPackageUseInfo(mBarUser0);
+        assertNotNull(pui);
+        assertTrue(pui.isUsedByOtherApps());
+        assertTrue(pui.getDexUseInfoMap().isEmpty());
+    }
+
+    @Test
+    public void testNotifySecondary() {
+        // Foo loads its own secondary files.
+        List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
+        notifyDexLoad(mFooUser0, fooSecondaries, mUser0);
+
+        PackageUseInfo pui = getPackageUseInfo(mFooUser0);
+        assertNotNull(pui);
+        assertFalse(pui.isUsedByOtherApps());
+        assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size());
+        assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0);
+    }
+
+    @Test
+    public void testNotifySecondaryForeign() {
+        // Foo loads bar secondary files.
+        List<String> barSecondaries = mBarUser0.getSecondaryDexPaths();
+        notifyDexLoad(mFooUser0, barSecondaries, mUser0);
+
+        PackageUseInfo pui = getPackageUseInfo(mBarUser0);
+        assertNotNull(pui);
+        assertFalse(pui.isUsedByOtherApps());
+        assertEquals(barSecondaries.size(), pui.getDexUseInfoMap().size());
+        assertSecondaryUse(mFooUser0, pui, barSecondaries, /*isUsedByOtherApps*/true, mUser0);
+    }
+
+    @Test
+    public void testNotifySequence() {
+        // Foo loads its own secondary files.
+        List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
+        notifyDexLoad(mFooUser0, fooSecondaries, mUser0);
+        // Foo loads Bar own secondary files.
+        List<String> barSecondaries = mBarUser0.getSecondaryDexPaths();
+        notifyDexLoad(mFooUser0, barSecondaries, mUser0);
+        // Foo loads Bar primary files.
+        notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0);
+        // Bar loads its own secondary files.
+        notifyDexLoad(mBarUser0, barSecondaries, mUser0);
+        // Bar loads some own secondary files which foo didn't load.
+        List<String> barSecondariesForOwnUse = mBarUser0.getSecondaryDexPathsForOwnUse();
+        notifyDexLoad(mBarUser0, barSecondariesForOwnUse, mUser0);
+
+        // Check bar usage. Should be used by other app (for primary and barSecondaries).
+        PackageUseInfo pui = getPackageUseInfo(mBarUser0);
+        assertNotNull(pui);
+        assertTrue(pui.isUsedByOtherApps());
+        assertEquals(barSecondaries.size() + barSecondariesForOwnUse.size(),
+                pui.getDexUseInfoMap().size());
+
+        assertSecondaryUse(mFooUser0, pui, barSecondaries, /*isUsedByOtherApps*/true, mUser0);
+        assertSecondaryUse(mFooUser0, pui, barSecondariesForOwnUse,
+                /*isUsedByOtherApps*/false, mUser0);
+
+        // Check foo usage. Should not be used by other app.
+        pui = getPackageUseInfo(mFooUser0);
+        assertNotNull(pui);
+        assertFalse(pui.isUsedByOtherApps());
+        assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size());
+        assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0);
+    }
+
+    @Test
+    public void testPackageUseInfoNotFound() {
+        // Assert we don't get back data we did not previously record.
+        assertNull(getPackageUseInfo(mFooUser0));
+    }
+
+    @Test
+    public void testInvalidIsa() {
+        // Notifying with an invalid ISA should be ignored.
+        notifyDexLoad(mInvalidIsa, mInvalidIsa.getSecondaryDexPaths(), mUser0);
+        assertNull(getPackageUseInfo(mInvalidIsa));
+    }
+
+    @Test
+    public void testNotExistingPackate() {
+        // Notifying about the load of a package which was previously not
+        // register in DexManager#load should be ignored.
+        notifyDexLoad(mDoesNotExist, mDoesNotExist.getBaseAndSplitDexPaths(), mUser0);
+        assertNull(getPackageUseInfo(mDoesNotExist));
+    }
+
+    @Test
+    public void testCrossUserAttempt() {
+        // Bar from User1 tries to load secondary dex files from User0 Bar.
+        // Request should be ignored.
+        notifyDexLoad(mBarUser1, mBarUser0.getSecondaryDexPaths(), mUser1);
+        assertNull(getPackageUseInfo(mBarUser1));
+    }
+
+    @Test
+    public void testPackageNotInstalledForUser() {
+        // User1 tries to load Foo which is installed for User0 but not for User1.
+        // Note that the PackageManagerService already filters this out but we
+        // still check that nothing goes unexpected in DexManager.
+        notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser1);
+        assertNull(getPackageUseInfo(mBarUser1));
+    }
+
+    private void assertSecondaryUse(TestData testData, PackageUseInfo pui,
+            List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId) {
+        for (String dex : secondaries) {
+            DexUseInfo dui = pui.getDexUseInfoMap().get(dex);
+            assertNotNull(dui);
+            assertEquals(isUsedByOtherApps, dui.isUsedByOtherApps());
+            assertEquals(ownerUserId, dui.getOwnerUserId());
+            assertEquals(1, dui.getLoaderIsas().size());
+            assertTrue(dui.getLoaderIsas().contains(testData.mLoaderIsa));
+        }
+    }
+
+    private void notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId) {
+        mDexManager.notifyDexLoad(testData.mPackageInfo.applicationInfo, dexPaths,
+                testData.mLoaderIsa, loaderUserId);
+    }
+
+    private PackageUseInfo getPackageUseInfo(TestData testData) {
+        return mDexManager.getPackageUseInfo(testData.mPackageInfo.packageName);
+    }
+
+    private static PackageInfo getMockPackageInfo(String packageName, int userId) {
+        PackageInfo pi = new PackageInfo();
+        pi.packageName = packageName;
+        pi.applicationInfo = getMockApplicationInfo(packageName, userId);
+        return pi;
+    }
+
+    private static ApplicationInfo getMockApplicationInfo(String packageName, int userId) {
+        ApplicationInfo ai = new ApplicationInfo();
+        String codeDir = "/data/app/" + packageName;
+        ai.setBaseCodePath(codeDir + "/base.dex");
+        ai.setSplitCodePaths(new String[] {codeDir + "/split-1.dex", codeDir + "/split-2.dex"});
+        ai.dataDir = "/data/user/" + userId + "/" + packageName;
+        ai.packageName = packageName;
+        return ai;
+    }
+
+    private static class TestData {
+        private final PackageInfo mPackageInfo;
+        private final String mLoaderIsa;
+
+        private TestData(String  packageName, String loaderIsa, int userId) {
+            mPackageInfo = getMockPackageInfo(packageName, userId);
+            mLoaderIsa = loaderIsa;
+        }
+
+        private String getPackageName() {
+            return mPackageInfo.packageName;
+        }
+
+        List<String> getSecondaryDexPaths() {
+            List<String> paths = new ArrayList<>();
+            paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary1.dex");
+            paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary2.dex");
+            paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary3.dex");
+            return paths;
+        }
+
+        List<String> getSecondaryDexPathsForOwnUse() {
+            List<String> paths = new ArrayList<>();
+            paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary4.dex");
+            paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary5.dex");
+            return paths;
+        }
+
+        List<String> getBaseAndSplitDexPaths() {
+            List<String> paths = new ArrayList<>();
+            paths.add(mPackageInfo.applicationInfo.sourceDir);
+            for (String split : mPackageInfo.applicationInfo.splitSourceDirs) {
+                paths.add(split);
+            }
+            return paths;
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
new file mode 100644
index 0000000..5a42841
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.dex;
+
+import android.os.Build;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import dalvik.system.VMRuntime;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
+import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class PackageDexUsageTests {
+    private PackageDexUsage mPackageDexUsage;
+
+    private TestData mFooBaseUser0;
+    private TestData mFooSplit1User0;
+    private TestData mFooSplit2UsedByOtherApps0;
+    private TestData mFooSecondary1User0;
+    private TestData mFooSecondary1User1;
+    private TestData mFooSecondary2UsedByOtherApps0;
+    private TestData mInvalidIsa;
+
+    private TestData mBarBaseUser0;
+    private TestData mBarSecondary1User0;
+    private TestData mBarSecondary2User1;
+
+    @Before
+    public void setup() {
+        mPackageDexUsage = new PackageDexUsage();
+
+        String fooPackageName = "com.google.foo";
+        String fooCodeDir = "/data/app/com.google.foo/";
+        String fooDataDir = "/data/user/0/com.google.foo/";
+
+        String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
+
+        mFooBaseUser0 = new TestData(fooPackageName,
+                fooCodeDir + "base.apk", 0, isa, false, true);
+
+        mFooSplit1User0 = new TestData(fooPackageName,
+                fooCodeDir + "split-1.apk", 0, isa, false, true);
+
+        mFooSplit2UsedByOtherApps0 = new TestData(fooPackageName,
+                fooCodeDir + "split-2.apk", 0, isa, true, true);
+
+        mFooSecondary1User0 = new TestData(fooPackageName,
+                fooDataDir + "sec-1.dex", 0, isa, false, false);
+
+        mFooSecondary1User1 = new TestData(fooPackageName,
+                fooDataDir + "sec-1.dex", 1, isa, false, false);
+
+        mFooSecondary2UsedByOtherApps0 = new TestData(fooPackageName,
+                fooDataDir + "sec-2.dex", 0, isa, true, false);
+
+        mInvalidIsa = new TestData(fooPackageName,
+                fooCodeDir + "base.apk", 0, "INVALID_ISA", false, true);
+
+        String barPackageName = "com.google.bar";
+        String barCodeDir = "/data/app/com.google.bar/";
+        String barDataDir = "/data/user/0/com.google.bar/";
+        String barDataDir1 = "/data/user/1/com.google.bar/";
+
+        mBarBaseUser0 = new TestData(barPackageName,
+                barCodeDir + "base.apk", 0, isa, false, true);
+        mBarSecondary1User0 = new TestData(barPackageName,
+                barDataDir + "sec-1.dex", 0, isa, false, false);
+        mBarSecondary2User1 = new TestData(barPackageName,
+                barDataDir1 + "sec-2.dex", 1, isa, false, false);
+    }
+
+    @Test
+    public void testRecordPrimary() {
+        // Assert new information.
+        assertTrue(record(mFooBaseUser0));
+
+        assertPackageDexUsage(mFooBaseUser0);
+        writeAndReadBack();
+        assertPackageDexUsage(mFooBaseUser0);
+    }
+
+    @Test
+    public void testRecordSplit() {
+        // Assert new information.
+        assertTrue(record(mFooSplit1User0));
+
+        assertPackageDexUsage(mFooSplit1User0);
+        writeAndReadBack();
+        assertPackageDexUsage(mFooSplit1User0);
+    }
+
+    @Test
+    public void testRecordSplitPrimarySequence() {
+        // Assert new information.
+        assertTrue(record(mFooBaseUser0));
+        // Assert no new information.
+        assertFalse(record(mFooSplit1User0));
+
+        assertPackageDexUsage(mFooBaseUser0);
+        writeAndReadBack();
+        assertPackageDexUsage(mFooBaseUser0);
+
+        // Write Split2 which is used by other apps.
+        // Assert new information.
+        assertTrue(record(mFooSplit2UsedByOtherApps0));
+        assertPackageDexUsage(mFooSplit2UsedByOtherApps0);
+        writeAndReadBack();
+        assertPackageDexUsage(mFooSplit2UsedByOtherApps0);
+    }
+
+    @Test
+    public void testRecordSecondary() {
+        assertTrue(record(mFooSecondary1User0));
+
+        assertPackageDexUsage(null, mFooSecondary1User0);
+        writeAndReadBack();
+        assertPackageDexUsage(null, mFooSecondary1User0);
+
+        // Recording again does not add more data.
+        assertFalse(record(mFooSecondary1User0));
+        assertPackageDexUsage(null, mFooSecondary1User0);
+    }
+
+    @Test
+    public void testRecordBaseAndSecondarySequence() {
+        // Write split.
+        assertTrue(record(mFooSplit2UsedByOtherApps0));
+        // Write secondary.
+        assertTrue(record(mFooSecondary1User0));
+
+        // Check.
+        assertPackageDexUsage(mFooSplit2UsedByOtherApps0, mFooSecondary1User0);
+        writeAndReadBack();
+        assertPackageDexUsage(mFooSplit2UsedByOtherApps0, mFooSecondary1User0);
+
+        // Write another secondary.
+        assertTrue(record(mFooSecondary2UsedByOtherApps0));
+
+        // Check.
+        assertPackageDexUsage(
+                mFooSplit2UsedByOtherApps0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0);
+        writeAndReadBack();
+        assertPackageDexUsage(
+                mFooSplit2UsedByOtherApps0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0);
+    }
+
+    @Test
+    public void testMultiplePackages() {
+        assertTrue(record(mFooBaseUser0));
+        assertTrue(record(mFooSecondary1User0));
+        assertTrue(record(mFooSecondary2UsedByOtherApps0));
+        assertTrue(record(mBarBaseUser0));
+        assertTrue(record(mBarSecondary1User0));
+        assertTrue(record(mBarSecondary2User1));
+
+        assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0);
+        assertPackageDexUsage(mBarBaseUser0, mBarSecondary1User0, mBarSecondary2User1);
+        writeAndReadBack();
+        assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0);
+        assertPackageDexUsage(mBarBaseUser0, mBarSecondary1User0, mBarSecondary2User1);
+    }
+
+    @Test
+    public void testPackageNotFound() {
+        assertNull(mPackageDexUsage.getPackageUseInfo("missing.package"));
+    }
+
+    @Test
+    public void testAttemptToChangeOwner() {
+        assertTrue(record(mFooSecondary1User0));
+        try {
+            record(mFooSecondary1User1);
+            fail("Expected exception");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testInvalidIsa() {
+        try {
+            record(mInvalidIsa);
+            fail("Expected exception");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testReadWriteEmtpy() {
+        // Expect no exceptions when writing/reading without data.
+        writeAndReadBack();
+    }
+
+    @Test
+    public void testSyncData() {
+        // Write some records.
+        assertTrue(record(mFooBaseUser0));
+        assertTrue(record(mFooSecondary1User0));
+        assertTrue(record(mFooSecondary2UsedByOtherApps0));
+        assertTrue(record(mBarBaseUser0));
+        assertTrue(record(mBarSecondary1User0));
+        assertTrue(record(mBarSecondary2User1));
+
+        // Verify all is good.
+        assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0);
+        assertPackageDexUsage(mBarBaseUser0, mBarSecondary1User0, mBarSecondary2User1);
+        writeAndReadBack();
+        assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0);
+        assertPackageDexUsage(mBarBaseUser0, mBarSecondary1User0, mBarSecondary2User1);
+
+        // Simulate that only user 1 is available.
+        Map<String, Set<Integer>> packageToUsersMap = new HashMap<>();
+        packageToUsersMap.put(mBarSecondary2User1.mPackageName,
+                new HashSet<>(Arrays.asList(mBarSecondary2User1.mOwnerUserId)));
+        mPackageDexUsage.syncData(packageToUsersMap);
+
+        // Assert that only user 1 files are there.
+        assertPackageDexUsage(mBarBaseUser0, mBarSecondary2User1);
+        assertNull(mPackageDexUsage.getPackageUseInfo(mFooBaseUser0.mPackageName));
+    }
+
+    private void assertPackageDexUsage(TestData primary, TestData... secondaries) {
+        String packageName = primary == null ? secondaries[0].mPackageName : primary.mPackageName;
+        boolean primaryUsedByOtherApps = primary == null ? false : primary.mUsedByOtherApps;
+        PackageUseInfo pInfo = mPackageDexUsage.getPackageUseInfo(packageName);
+
+        // Check package use info
+        assertNotNull(pInfo);
+        assertEquals(primaryUsedByOtherApps, pInfo.isUsedByOtherApps());
+        Map<String, DexUseInfo> dexUseInfoMap = pInfo.getDexUseInfoMap();
+        assertEquals(secondaries.length, dexUseInfoMap.size());
+
+        // Check dex use info
+        for (TestData testData : secondaries) {
+            DexUseInfo dInfo = dexUseInfoMap.get(testData.mDexFile);
+            assertNotNull(dInfo);
+            assertEquals(testData.mUsedByOtherApps, dInfo.isUsedByOtherApps());
+            assertEquals(testData.mOwnerUserId, dInfo.getOwnerUserId());
+            assertEquals(1, dInfo.getLoaderIsas().size());
+            assertTrue(dInfo.getLoaderIsas().contains(testData.mLoaderIsa));
+        }
+    }
+
+    private boolean record(TestData testData) {
+        return mPackageDexUsage.record(testData.mPackageName, testData.mDexFile,
+                testData.mOwnerUserId, testData.mLoaderIsa, testData.mUsedByOtherApps,
+                testData.mPrimaryOrSplit);
+    }
+
+    private void writeAndReadBack() {
+        try {
+            StringWriter writer = new StringWriter();
+            mPackageDexUsage.write(writer);
+
+            mPackageDexUsage = new PackageDexUsage();
+            mPackageDexUsage.read(new StringReader(writer.toString()));
+        } catch (IOException e) {
+            fail("Unexpected IOException: " + e.getMessage());
+        }
+    }
+
+    private static class TestData {
+        private final String mPackageName;
+        private final String mDexFile;
+        private final int mOwnerUserId;
+        private final String mLoaderIsa;
+        private final boolean mUsedByOtherApps;
+        private final boolean mPrimaryOrSplit;
+
+        private TestData(String packageName, String dexFile, int ownerUserId,
+                 String loaderIsa, boolean isUsedByOtherApps, boolean primaryOrSplit) {
+            mPackageName = packageName;
+            mDexFile = dexFile;
+            mOwnerUserId = ownerUserId;
+            mLoaderIsa = loaderIsa;
+            mUsedByOtherApps = isUsedByOtherApps;
+            mPrimaryOrSplit = primaryOrSplit;
+        }
+
+    }
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 2c16ca0..a6da9e9 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -843,6 +843,58 @@
             "signal_pco_receiver_string_array";
 
     /**
+     * Defines carrier-specific actions which act upon
+     * android.intent.action.CARRIER_SIGNAL_REDIRECTED, used for customization of the
+     * default carrier app
+     * Format: "CARRIER_ACTION_IDX, ..."
+     * Where {@code CARRIER_ACTION_IDX} is an integer defined in
+     * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils}
+     * Example:
+     * {@link com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_DISABLE_METERED_APNS
+     * disable_metered_apns}
+     * @hide
+     */
+    public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY =
+            "carrier_default_actions_on_redirection_string_array";
+
+    /**
+     * Defines carrier-specific actions which act upon
+     * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
+     * and configured signal args:
+     * {@link com.android.internal.telephony.TelephonyIntents#EXTRA_APN_TYPE_KEY apnType},
+     * {@link com.android.internal.telephony.TelephonyIntents#EXTRA_ERROR_CODE_KEY errorCode}
+     * used for customization of the default carrier app
+     * Format:
+     * {
+     *     "APN_1, ERROR_CODE_1 : CARRIER_ACTION_IDX_1, CARRIER_ACTION_IDX_2...",
+     *     "APN_1, ERROR_CODE_2 : CARRIER_ACTION_IDX_1 "
+     * }
+     * Where {@code APN_1} is a string defined in
+     * {@link com.android.internal.telephony.PhoneConstants PhoneConstants}
+     * Example: "default"
+     *
+     * {@code ERROR_CODE_1} is an integer defined in
+     * {@link com.android.internal.telephony.dataconnection.DcFailCause DcFailure}
+     * Example:
+     * {@link com.android.internal.telephony.dataconnection.DcFailCause#MISSING_UNKNOWN_APN}
+     *
+     * {@code CARRIER_ACTION_IDX_1} is an integer defined in
+     * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils}
+     * Example:
+     * {@link com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_DISABLE_METERED_APNS}
+     * @hide
+     */
+    public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DCFAILURE_STRING_ARRAY =
+            "carrier_default_actions_on_dcfailure_string_array";
+
+    /**
+     * Defines a list of acceptable redirection url for default carrier app
+     * @hides
+     */
+    public static final String KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY =
+            "carrier_default_redirection_url_string_array";
+
+    /**
      * Determines whether the carrier supports making non-emergency phone calls while the phone is
      * in emergency callback mode.  Default value is {@code true}, meaning that non-emergency calls
      * are allowed in emergency callback mode.
@@ -905,6 +957,13 @@
     public static final int CDMA_ROAMING_MODE_AFFILIATED = 1;
     /** @hide */
     public static final int CDMA_ROAMING_MODE_ANY = 2;
+    /**
+     * Boolean indicating if support is provided for directly dialing FDN number from FDN list.
+     * If false, this feature is not supported.
+     * @hide
+     */
+    public static final String KEY_SUPPORT_DIRECT_FDN_DIALING_BOOL =
+            "support_direct_fdn_dialing_bool";
 
     /**
      * Report IMEI as device id even if it's a CDMA/LTE phone.
@@ -1034,7 +1093,7 @@
      * is returned.
      * @hide
      */
-    public static final String FILTERED_CNAP_NAMES_STRING_ARRAY = "filtered_cnap_names_string_array";
+    public static final String KEY_FILTERED_CNAP_NAMES_STRING_ARRAY = "filtered_cnap_names_string_array";
 
     /**
      * Determine whether user can change Wi-Fi Calling preference in roaming.
@@ -1176,6 +1235,7 @@
         sDefaults.putBoolean(KEY_CONFIG_WIFI_DISABLE_IN_ECBM, false);
         sDefaults.putBoolean(KEY_CARRIER_NAME_OVERRIDE_BOOL, false);
         sDefaults.putString(KEY_CARRIER_NAME_STRING, "");
+        sDefaults.putBoolean(KEY_SUPPORT_DIRECT_FDN_DIALING_BOOL, false);
 
         // MMS defaults
         sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false);
@@ -1221,6 +1281,15 @@
         sDefaults.putStringArray(KEY_SIGNAL_PCO_RECEIVER_STRING_ARRAY, null);
         sDefaults.putString(KEY_CARRIER_SETUP_APP_STRING, "");
 
+        // Default carrier app configurations
+        sDefaults.putStringArray(KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY,
+                new String[]{
+                        "4, 1"
+                        //4: CARRIER_ACTION_DISABLE_METERED_APNS
+                        //1: CARRIER_ACTION_SHOW_PORTAL_NOTIFICATION
+                });
+        sDefaults.putStringArray(KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY, null);
+
         // Rat families: {GPRS, EDGE}, {EVDO, EVDO_A, EVDO_B}, {UMTS, HSPA, HSDPA, HSUPA, HSPAP},
         // {LTE, LTE_CA}
         // Order is important - lowest precidence first
@@ -1236,7 +1305,7 @@
         sDefaults.putStringArray(KEY_IMS_REASONINFO_MAPPING_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_ENHANCED_4G_LTE_TITLE_VARIANT_BOOL, false);
         sDefaults.putBoolean(KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL, false);
-        sDefaults.putStringArray(FILTERED_CNAP_NAMES_STRING_ARRAY, null);
+        sDefaults.putStringArray(KEY_FILTERED_CNAP_NAMES_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, false);
     }
 
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index 0334254..811c996 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -233,6 +233,13 @@
      */
     public static final int DIALED_ON_WRONG_SLOT = 56;
 
+    /**
+     * The network does not accept the emergency call request because IMEI was used as
+     * identification and this cability is not supported by the network.
+     * {@hide}
+     */
+    public static final int IMEI_NOT_ACCEPTED = 57;
+
     //*********************************************************************************************
     // When adding a disconnect type:
     // 1) Please assign the new type the next id value below.
@@ -241,14 +248,14 @@
     // 4) Update toString() with the newly added disconnect type.
     // 5) Update android.telecom.DisconnectCauseUtil with any mappings to a telecom.DisconnectCause.
     //
-    // NextId: 57
+    // NextId: 58
     //*********************************************************************************************
 
     /** Smallest valid value for call disconnect codes. */
     public static final int MINIMUM_VALID_VALUE = NOT_DISCONNECTED;
 
     /** Largest valid value for call disconnect codes. */
-    public static final int MAXIMUM_VALID_VALUE = DIALED_ON_WRONG_SLOT;
+    public static final int MAXIMUM_VALID_VALUE = IMEI_NOT_ACCEPTED;
 
     /** Private constructor to avoid class instantiation. */
     private DisconnectCause() {
@@ -370,6 +377,8 @@
             return "DATA_LIMIT_REACHED";
         case DIALED_ON_WRONG_SLOT:
             return "DIALED_ON_WRONG_SLOT";
+        case IMEI_NOT_ACCEPTED:
+            return "IMEI_NOT_ACCEPTED";
         default:
             return "INVALID: " + cause;
         }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 4c8eda0..5a15009 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -905,8 +905,10 @@
      *
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *
+     * @hide
      */
-    /** {@hide} */
+    @SystemApi
     public String getImei() {
         return getImei(getDefaultSim());
     }
@@ -918,8 +920,10 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      *
      * @param slotId of which deviceID is returned
+     *
+     * @hide
      */
-    /** {@hide} */
+    @SystemApi
     public String getImei(int slotId) {
         ITelephony telephony = getITelephony();
         if (telephony == null) return null;
diff --git a/services/tests/servicestests/src/android/net/util/BlockingSocketReaderTest.java b/tests/net/java/android/net/util/BlockingSocketReaderTest.java
similarity index 100%
rename from services/tests/servicestests/src/android/net/util/BlockingSocketReaderTest.java
rename to tests/net/java/android/net/util/BlockingSocketReaderTest.java
diff --git a/services/tests/servicestests/src/android/net/util/ConnectivityPacketSummaryTest.java b/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java
similarity index 100%
rename from services/tests/servicestests/src/android/net/util/ConnectivityPacketSummaryTest.java
rename to tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index d62c30d..46b6403 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -1103,6 +1103,29 @@
         UNAVAILABLE
     }
 
+    private static class CallbackInfo {
+        public final CallbackState state;
+        public final Network network;
+        public final Object arg;
+        public CallbackInfo(CallbackState s, Network n, Object o) {
+            state = s; network = n; arg = o;
+        }
+        public String toString() {
+            return String.format("%s (%s)", state, network);
+        }
+        @Override
+        public boolean equals(Object o) {
+            if (!(o instanceof CallbackInfo)) return false;
+            // Ignore timeMs, since it's unpredictable.
+            CallbackInfo other = (CallbackInfo) o;
+            return (state == other.state) && Objects.equals(network, other.network);
+        }
+        @Override
+        public int hashCode() {
+            return Objects.hash(state, network);
+        }
+    }
+
     /**
      * Utility NetworkCallback for testing. The caller must explicitly test for all the callbacks
      * this class receives, by calling expectCallback() exactly once each time a callback is
@@ -1114,21 +1137,6 @@
         // the linger timeout.
         private final static int TIMEOUT_MS = 50;
 
-        private class CallbackInfo {
-            public final CallbackState state;
-            public final Network network;
-            public Object arg;
-            public CallbackInfo(CallbackState s, Network n, Object o) {
-                state = s; network = n; arg = o;
-            }
-            public String toString() { return String.format("%s (%s)", state, network); }
-            public boolean equals(Object o) {
-                if (!(o instanceof CallbackInfo)) return false;
-                // Ignore timeMs, since it's unpredictable.
-                CallbackInfo other = (CallbackInfo) o;
-                return state == other.state && Objects.equals(network, other.network);
-            }
-        }
         private final LinkedBlockingQueue<CallbackInfo> mCallbacks = new LinkedBlockingQueue<>();
 
         protected void setLastCallback(CallbackState state, Network network, Object o) {
@@ -1155,17 +1163,24 @@
             setLastCallback(CallbackState.LOST, network, null);
         }
 
+        CallbackInfo nextCallback(int timeoutMs) {
+            CallbackInfo cb = null;
+            try {
+                cb = mCallbacks.poll(timeoutMs, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException e) {
+            }
+            if (cb == null) {
+                // LinkedBlockingQueue.poll() returns null if it timeouts.
+                fail("Did not receive callback after " + timeoutMs + "ms");
+            }
+            return cb;
+        }
+
         void expectCallback(CallbackState state, MockNetworkAgent mockAgent, int timeoutMs) {
             CallbackInfo expected = new CallbackInfo(
                     state, (mockAgent != null) ? mockAgent.getNetwork() : null, 0);
-            CallbackInfo actual;
-            try {
-                actual = mCallbacks.poll(timeoutMs, TimeUnit.MILLISECONDS);
-                assertEquals("Unexpected callback:", expected, actual);
-            } catch (InterruptedException e) {
-                fail("Did not receive expected " + expected + " after " + TIMEOUT_MS + "ms");
-                actual = null;  // Or the compiler can't tell it's never used uninitialized.
-            }
+            CallbackInfo actual = nextCallback(timeoutMs);
+            assertEquals("Unexpected callback:", expected, actual);
             if (state == CallbackState.LOSING) {
                 String msg = String.format(
                         "Invalid linger time value %d, must be between %d and %d",
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
new file mode 100644
index 0000000..b2a9a49
--- /dev/null
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.reset;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.IConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class UpstreamNetworkMonitorTest {
+    private static final int EVENT_UNM_UPDATE = 1;
+
+    @Mock private Context mContext;
+    @Mock private IConnectivityManager mCS;
+
+    private TestConnectivityManager mCM;
+    private UpstreamNetworkMonitor mUNM;
+
+    @Before public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        reset(mContext);
+        reset(mCS);
+
+        mCM = new TestConnectivityManager(mContext, mCS);
+        mUNM = new UpstreamNetworkMonitor(null, EVENT_UNM_UPDATE, (ConnectivityManager) mCM);
+    }
+
+    @Test
+    public void testDoesNothingBeforeStarted() {
+        UpstreamNetworkMonitor unm = new UpstreamNetworkMonitor(null, null, EVENT_UNM_UPDATE);
+        assertFalse(unm.mobileNetworkRequested());
+        // Given a null Context, and therefore a null ConnectivityManager,
+        // these would cause an exception, if they actually attempted anything.
+        unm.mobileUpstreamRequiresDun(true);
+        unm.mobileUpstreamRequiresDun(false);
+    }
+
+    @Test
+    public void testDefaultNetworkIsTracked() throws Exception {
+        assertEquals(0, mCM.trackingDefault.size());
+
+        mUNM.start();
+        assertEquals(1, mCM.trackingDefault.size());
+
+        mUNM.stop();
+        assertTrue(mCM.isEmpty());
+    }
+
+    @Test
+    public void testListensForDunNetworks() throws Exception {
+        assertTrue(mCM.listening.isEmpty());
+
+        mUNM.start();
+        assertFalse(mCM.listening.isEmpty());
+        assertTrue(mCM.isListeningForDun());
+
+        mUNM.stop();
+        assertTrue(mCM.isEmpty());
+    }
+
+    @Test
+    public void testCanRequestMobileNetwork() throws Exception {
+        assertFalse(mUNM.mobileNetworkRequested());
+        assertEquals(0, mCM.requested.size());
+
+        mUNM.start();
+        assertFalse(mUNM.mobileNetworkRequested());
+        assertEquals(0, mCM.requested.size());
+
+        mUNM.mobileUpstreamRequiresDun(false);
+        assertFalse(mUNM.mobileNetworkRequested());
+        assertEquals(0, mCM.requested.size());
+
+        mUNM.registerMobileNetworkRequest();
+        assertTrue(mUNM.mobileNetworkRequested());
+        assertEquals(1, mCM.requested.size());
+        assertFalse(mCM.isDunRequested());
+
+        mUNM.stop();
+        assertFalse(mUNM.mobileNetworkRequested());
+        assertTrue(mCM.isEmpty());
+    }
+
+    @Test
+    public void testCanRequestDunNetwork() throws Exception {
+        assertFalse(mUNM.mobileNetworkRequested());
+        assertEquals(0, mCM.requested.size());
+
+        mUNM.start();
+        assertFalse(mUNM.mobileNetworkRequested());
+        assertEquals(0, mCM.requested.size());
+
+        mUNM.mobileUpstreamRequiresDun(true);
+        assertFalse(mUNM.mobileNetworkRequested());
+        assertEquals(0, mCM.requested.size());
+
+        mUNM.registerMobileNetworkRequest();
+        assertTrue(mUNM.mobileNetworkRequested());
+        assertEquals(1, mCM.requested.size());
+        assertTrue(mCM.isDunRequested());
+
+        mUNM.stop();
+        assertFalse(mUNM.mobileNetworkRequested());
+        assertTrue(mCM.isEmpty());
+    }
+
+    private static class TestConnectivityManager extends ConnectivityManager {
+        public Set<NetworkCallback> trackingDefault = new HashSet<>();
+        public Map<NetworkCallback, NetworkRequest> listening = new HashMap<>();
+        public Map<NetworkCallback, NetworkRequest> requested = new HashMap<>();
+
+        public TestConnectivityManager(Context ctx, IConnectivityManager svc) {
+            super(ctx, svc);
+        }
+
+        boolean isEmpty() {
+            return trackingDefault.isEmpty() &&
+                   listening.isEmpty() &&
+                   requested.isEmpty();
+        }
+
+        boolean isListeningForDun() {
+            for (NetworkRequest req : listening.values()) {
+                if (req.networkCapabilities.hasCapability(NET_CAPABILITY_DUN)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        boolean isDunRequested() {
+            for (NetworkRequest req : requested.values()) {
+                if (req.networkCapabilities.hasCapability(NET_CAPABILITY_DUN)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public void requestNetwork(NetworkRequest req, NetworkCallback cb) {
+            assertFalse(requested.containsKey(cb));
+            requested.put(cb, req);
+        }
+
+        @Override
+        public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb) {
+            assertFalse(listening.containsKey(cb));
+            listening.put(cb, req);
+        }
+
+        @Override
+        public void registerDefaultNetworkCallback(NetworkCallback cb) {
+            assertFalse(trackingDefault.contains(cb));
+            trackingDefault.add(cb);
+        }
+
+        @Override
+        public void unregisterNetworkCallback(NetworkCallback cb) {
+            if (trackingDefault.contains(cb)) {
+                trackingDefault.remove(cb);
+            } else if (listening.containsKey(cb)) {
+                listening.remove(cb);
+            } else if (requested.containsKey(cb)) {
+                requested.remove(cb);
+            }
+
+            assertFalse(trackingDefault.contains(cb));
+            assertFalse(listening.containsKey(cb));
+            assertFalse(requested.containsKey(cb));
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 9e897bf..18c1245 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -59,7 +59,7 @@
 
     int addOrUpdateNetwork(in WifiConfiguration config);
 
-    boolean addPasspointConfiguration(in PasspointConfiguration config);
+    boolean addOrUpdatePasspointConfiguration(in PasspointConfiguration config);
 
     boolean removePasspointConfiguration(in String fqdn);
 
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 3b7f721..958279b 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -608,6 +608,7 @@
      * if there has been a report of it having no internet access, and, it never have had
      * internet access in the past.
      */
+    @SystemApi
     public boolean hasNoInternetAccess() {
         return numNoInternetAccessReports > 0 && !validatedInternetAccess;
     }
@@ -621,6 +622,17 @@
     public boolean noInternetAccessExpected;
 
     /**
+     * The WiFi configuration is expected not to have Internet access (e.g., a wireless printer, a
+     * Chromecast hotspot, etc.). This will be set if the user explicitly confirms a connection to
+     * this configuration and selects "don't ask again".
+     * @hide
+     */
+    @SystemApi
+    public boolean isNoInternetAccessExpected() {
+        return noInternetAccessExpected;
+    }
+
+    /**
      * @hide
      * Last time the system was connected to this configuration.
      */
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 674c161..ab6b3e3 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -842,31 +842,31 @@
     }
 
     /**
-     * Add a Passpoint configuration.  The configuration provides a credential
+     * Add or update a Passpoint configuration.  The configuration provides a credential
      * for connecting to Passpoint networks that are operated by the Passpoint
      * service provider specified in the configuration.
      *
      * Each configuration is uniquely identified by its FQDN (Fully Qualified Domain
-     * Name).  In the case when there is an existing configuration with the same base
-     * domain, the new configuration will replace the existing configuration.
+     * Name).  In the case when there is an existing configuration with the same
+     * FQDN, the new configuration will replace the existing configuration.
      *
      * @param config The Passpoint configuration to be added
-     * @return true on success or false on failure
+     * @return true on success
      * @hide
      */
-    public boolean addPasspointConfiguration(PasspointConfiguration config) {
+    public boolean addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
         try {
-            return mService.addPasspointConfiguration(config);
+            return mService.addOrUpdatePasspointConfiguration(config);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Remove a Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
+     * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
      *
      * @param fqdn The FQDN of the passpoint configuration to be removed
-     * @return true on success or false on failure
+     * @return true on success
      * @hide
      */
     public boolean removePasspointConfiguration(String fqdn) {
@@ -880,7 +880,9 @@
     /**
      * Return the list of installed Passpoint configurations.
      *
-     * @return A list of PasspointConfiguration or null
+     * An empty list will be returned when no configurations are installed.
+     *
+     * @return A list of {@link PasspointConfiguration}
      * @hide
      */
     public List<PasspointConfiguration> getPasspointConfigurations() {
@@ -1073,7 +1075,6 @@
         }
     }
 
-    /* Keep this list in sync with wifi_hal.h */
     /** @hide */
     public static final int WIFI_FEATURE_INFRA            = 0x0001;  // Basic infrastructure mode
     /** @hide */
@@ -1087,7 +1088,7 @@
     /** @hide */
     public static final int WIFI_FEATURE_SCANNER          = 0x0020;  // WifiScanner APIs
     /** @hide */
-    public static final int WIFI_FEATURE_AWARE              = 0x0040;  // Wi-Fi AWare networking
+    public static final int WIFI_FEATURE_AWARE            = 0x0040;  // Wi-Fi AWare networking
     /** @hide */
     public static final int WIFI_FEATURE_D2D_RTT          = 0x0080;  // Device-to-device RTT
     /** @hide */
@@ -1105,13 +1106,28 @@
     /** @hide */
     public static final int WIFI_FEATURE_EPR              = 0x4000;  // Enhanced power reporting
     /** @hide */
-    public static final int WIFI_FEATURE_AP_STA            = 0x8000;  // Support for AP STA Concurrency
+    public static final int WIFI_FEATURE_AP_STA           = 0x8000;  // AP STA Concurrency
     /** @hide */
-    public static final int WIFI_FEATURE_LINK_LAYER_STATS  = 0x10000; // Link layer stats collection
+    public static final int WIFI_FEATURE_LINK_LAYER_STATS = 0x10000; // Link layer stats collection
     /** @hide */
-    public static final int WIFI_FEATURE_LOGGER            = 0x20000; // WiFi Logger
+    public static final int WIFI_FEATURE_LOGGER           = 0x20000; // WiFi Logger
     /** @hide */
-    public static final int WIFI_FEATURE_HAL_EPNO          = 0x40000; // WiFi PNO enhanced
+    public static final int WIFI_FEATURE_HAL_EPNO         = 0x40000; // Enhanced PNO
+    /** @hide */
+    public static final int WIFI_FEATURE_RSSI_MONITOR     = 0x80000; // RSSI Monitor
+    /** @hide */
+    public static final int WIFI_FEATURE_MKEEP_ALIVE      = 0x100000; // mkeep_alive
+    /** @hide */
+    public static final int WIFI_FEATURE_CONFIG_NDO       = 0x200000; // ND offload
+    /** @hide */
+    public static final int WIFI_FEATURE_TRANSMIT_POWER   = 0x400000; // Capture transmit power
+    /** @hide */
+    public static final int WIFI_FEATURE_CONTROL_ROAMING  = 0x800000; // Control firmware roaming
+    /** @hide */
+    public static final int WIFI_FEATURE_IE_WHITELIST     = 0x1000000; // Probe IE white listing
+    /** @hide */
+    public static final int WIFI_FEATURE_SCAN_RAND        = 0x2000000; // Random MAC & Probe seq
+
 
     private int getSupportedFeatures() {
         try {
@@ -1763,6 +1779,7 @@
      * Interface for callback invocation on an application action
      * @hide
      */
+    @SystemApi
     public interface ActionListener {
         /** The operation succeeded */
         public void onSuccess();
@@ -1974,6 +1991,7 @@
      *
      * @hide
      */
+    @SystemApi
     public void connect(WifiConfiguration config, ActionListener listener) {
         if (config == null) throw new IllegalArgumentException("config cannot be null");
         // Use INVALID_NETWORK_ID for arg1 when passing a config object
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java b/wifi/java/android/net/wifi/aware/AttachCallback.java
similarity index 76%
rename from wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java
rename to wifi/java/android/net/wifi/aware/AttachCallback.java
index 1e8dbd9..c368b46 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java
+++ b/wifi/java/android/net/wifi/aware/AttachCallback.java
@@ -18,16 +18,14 @@
 
 /**
  * Base class for Aware attach callbacks. Should be extended by applications and set when calling
- * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)}. These are callbacks
+ * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)}. These are callbacks
  * applying to the Aware connection as a whole - not to specific publish or subscribe sessions -
- * for that see {@link WifiAwareDiscoverySessionCallback}.
- *
- * @hide PROPOSED_AWARE_API
+ * for that see {@link DiscoverySessionCallback}.
  */
-public class WifiAwareAttachCallback {
+public class AttachCallback {
     /**
      * Called when Aware attach operation
-     * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)}
+     * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)}
      * is completed and that we can now start discovery sessions or connections.
      *
      * @param session The Aware object on which we can execute further Aware operations - e.g.
@@ -39,7 +37,7 @@
 
     /**
      * Called when Aware attach operation
-     * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)} failed.
+     * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)} failed.
      */
     public void onAttachFailed() {
         /* empty */
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl b/wifi/java/android/net/wifi/aware/Characteristics.aidl
similarity index 94%
rename from wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
rename to wifi/java/android/net/wifi/aware/Characteristics.aidl
index a35e71d..77305e9 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
+++ b/wifi/java/android/net/wifi/aware/Characteristics.aidl
@@ -16,4 +16,4 @@
 
 package android.net.wifi.aware;
 
-parcelable WifiAwareCharacteristics;
+parcelable Characteristics;
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java b/wifi/java/android/net/wifi/aware/Characteristics.java
similarity index 82%
rename from wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
rename to wifi/java/android/net/wifi/aware/Characteristics.java
index 092aa34..70474fd 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
+++ b/wifi/java/android/net/wifi/aware/Characteristics.java
@@ -22,10 +22,8 @@
 
 /**
  * The characteristics of the Wi-Fi Aware implementation.
- *
- * @hide PROPOSED_AWARE_API
  */
-public class WifiAwareCharacteristics implements Parcelable {
+public final class Characteristics implements Parcelable {
     /** @hide */
     public static final String KEY_MAX_SERVICE_NAME_LENGTH = "key_max_service_name_length";
     /** @hide */
@@ -37,7 +35,7 @@
     private Bundle mCharacteristics = new Bundle();
 
     /** @hide : should not be created by apps */
-    public WifiAwareCharacteristics(Bundle characteristics) {
+    public Characteristics(Bundle characteristics) {
         mCharacteristics = characteristics;
     }
 
@@ -58,7 +56,7 @@
      * message exchange. Restricts the parameters of the
      * {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])},
      * {@link SubscribeConfig.Builder#setServiceSpecificInfo(byte[])}, and
-     * {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int, byte[])}
+     * {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])}
      * variants.
      *
      * @return A positive integer, maximum length of byte array for Aware messaging.
@@ -89,17 +87,17 @@
         return 0;
     }
 
-    public static final Creator<WifiAwareCharacteristics> CREATOR =
-            new Creator<WifiAwareCharacteristics>() {
+    public static final Creator<Characteristics> CREATOR =
+            new Creator<Characteristics>() {
                 @Override
-                public WifiAwareCharacteristics createFromParcel(Parcel in) {
-                    WifiAwareCharacteristics c = new WifiAwareCharacteristics(in.readBundle());
+                public Characteristics createFromParcel(Parcel in) {
+                    Characteristics c = new Characteristics(in.readBundle());
                     return c;
                 }
 
                 @Override
-                public WifiAwareCharacteristics[] newArray(int size) {
-                    return new WifiAwareCharacteristics[size];
+                public Characteristics[] newArray(int size) {
+                    return new Characteristics[size];
                 }
             };
 }
diff --git a/wifi/java/android/net/wifi/aware/ConfigRequest.java b/wifi/java/android/net/wifi/aware/ConfigRequest.java
index 4b21b15..6a5957b 100644
--- a/wifi/java/android/net/wifi/aware/ConfigRequest.java
+++ b/wifi/java/android/net/wifi/aware/ConfigRequest.java
@@ -22,7 +22,7 @@
 /**
  * Defines a request object to configure a Wi-Fi Aware network. Built using
  * {@link ConfigRequest.Builder}. Configuration is requested using
- * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)}.
+ * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)}.
  * Note that the actual achieved configuration may be different from the
  * requested configuration - since different applications may request different
  * configurations.
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java
similarity index 78%
rename from wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
rename to wifi/java/android/net/wifi/aware/DiscoverySession.java
index 2812ad4..adf189b 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SystemApi;
 import android.net.wifi.RttManager;
 import android.util.Log;
 
@@ -29,21 +28,19 @@
 /**
  * A class representing a single publish or subscribe Aware session. This object
  * will not be created directly - only its child classes are available:
- * {@link WifiAwarePublishDiscoverySession} and {@link WifiAwareSubscribeDiscoverySession}. This
+ * {@link PublishDiscoverySession} and {@link SubscribeDiscoverySession}. This
  * class provides functionality common to both publish and subscribe discovery sessions:
  * <ul>
- *     <li>Sending messages: {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[])} or
- *     {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[], int)} methods.
+ *     <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])} or
+ *     {@link #sendMessage(PeerHandle, int, byte[], int)} methods.
  *     <li>Creating a network-specifier when requesting a Aware connection:
- *     {@link #createNetworkSpecifier(WifiAwareManager.PeerHandle, byte[])}.
+ *     {@link #createNetworkSpecifier(PeerHandle, byte[])}.
  * </ul>
  * The {@link #destroy()} method must be called to destroy discovery sessions once they are
  * no longer needed.
- *
- * @hide PROPOSED_AWARE_API
  */
-public class WifiAwareDiscoveryBaseSession {
-    private static final String TAG = "WifiAwareDiscBaseSsn";
+public class DiscoverySession {
+    private static final String TAG = "DiscoverySession";
     private static final boolean DBG = false;
     private static final boolean VDBG = false; // STOPSHIP if true
 
@@ -62,7 +59,7 @@
 
     /**
      * Return the maximum permitted retry count when sending messages using
-     * {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[], int)}.
+     * {@link #sendMessage(PeerHandle, int, byte[], int)}.
      *
      * @return Maximum retry count when sending messages.
      */
@@ -71,7 +68,7 @@
     }
 
     /** @hide */
-    public WifiAwareDiscoveryBaseSession(WifiAwareManager manager, int clientId, int sessionId) {
+    public DiscoverySession(WifiAwareManager manager, int clientId, int sessionId) {
         if (VDBG) {
             Log.v(TAG, "New discovery session created: manager=" + manager + ", clientId="
                     + clientId + ", sessionId=" + sessionId);
@@ -93,7 +90,7 @@
      *     This operation must be done on a session which is no longer needed. Otherwise system
      *     resources will continue to be utilized until the application exits. The only
      *     exception is a session for which we received a termination callback,
-     *     {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)}.
+     *     {@link DiscoverySessionCallback#onSessionTerminated()}.
      */
     public void destroy() {
         WifiAwareManager mgr = mMgr.get();
@@ -139,23 +136,23 @@
     /**
      * Sends a message to the specified destination. Aware messages are transmitted in the context
      * of a discovery session - executed subsequent to a publish/subscribe
-     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
      * byte[], java.util.List)} event.
      * <p>
      *     Aware messages are not guaranteed delivery. Callbacks on
-     *     {@link WifiAwareDiscoverySessionCallback} indicate message was transmitted successfully,
-     *     {@link WifiAwareDiscoverySessionCallback#onMessageSendSucceeded(int)}, or transmission
+     *     {@link DiscoverySessionCallback} indicate message was transmitted successfully,
+     *     {@link DiscoverySessionCallback#onMessageSendSucceeded(int)}, or transmission
      *     failed (possibly after several retries) -
-     *     {@link WifiAwareDiscoverySessionCallback#onMessageSendFailed(int)}.
+     *     {@link DiscoverySessionCallback#onMessageSendFailed(int)}.
      * <p>
      *     The peer will get a callback indicating a message was received using
-     *     {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+     *     {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
      *     byte[])}.
      *
      * @param peerHandle The peer's handle for the message. Must be a result of an
-     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
      * byte[], java.util.List)} or
-     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
      * byte[])} events.
      * @param messageId An arbitrary integer used by the caller to identify the message. The same
      *            integer ID will be returned in the callbacks indicating message send success or
@@ -167,7 +164,7 @@
      *            (note: no retransmissions are attempted in other failure cases). A value of 0
      *            indicates no retries. Max permitted value is {@link #getMaxSendRetryCount()}.
      */
-    public void sendMessage(@NonNull WifiAwareManager.PeerHandle peerHandle, int messageId,
+    public void sendMessage(@NonNull PeerHandle peerHandle, int messageId,
             @Nullable byte[] message, int retryCount) {
         if (mTerminated) {
             Log.w(TAG, "sendMessage: called on terminated session");
@@ -186,25 +183,25 @@
     /**
      * Sends a message to the specified destination. Aware messages are transmitted in the context
      * of a discovery session - executed subsequent to a publish/subscribe
-     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
      * byte[], java.util.List)} event.
      * <p>
      *     Aware messages are not guaranteed delivery. Callbacks on
-     *     {@link WifiAwareDiscoverySessionCallback} indicate message was transmitted successfully,
-     *     {@link WifiAwareDiscoverySessionCallback#onMessageSendSucceeded(int)}, or transmission
+     *     {@link DiscoverySessionCallback} indicate message was transmitted successfully,
+     *     {@link DiscoverySessionCallback#onMessageSendSucceeded(int)}, or transmission
      *     failed (possibly after several retries) -
-     *     {@link WifiAwareDiscoverySessionCallback#onMessageSendFailed(int)}.
+     *     {@link DiscoverySessionCallback#onMessageSendFailed(int)}.
      * <p>
      * The peer will get a callback indicating a message was received using
-     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
      * byte[])}.
-     * Equivalent to {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[], int)}
+     * Equivalent to {@link #sendMessage(PeerHandle, int, byte[], int)}
      * with a {@code retryCount} of 0.
      *
      * @param peerHandle The peer's handle for the message. Must be a result of an
-     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
      * byte[], java.util.List)} or
-     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
      * byte[])} events.
      * @param messageId An arbitrary integer used by the caller to identify the message. The same
      *            integer ID will be returned in the callbacks indicating message send success or
@@ -212,16 +209,16 @@
      *                  can be arbitrary and non-unique.
      * @param message The message to be transmitted.
      */
-    public void sendMessage(@NonNull WifiAwareManager.PeerHandle peerHandle, int messageId,
+    public void sendMessage(@NonNull PeerHandle peerHandle, int messageId,
             @Nullable byte[] message) {
         sendMessage(peerHandle, messageId, message, 0);
     }
 
     /**
      * Start a ranging operation with the specified peers. The peer IDs are obtained from an
-     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
      * byte[], java.util.List)} or
-     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
      * byte[])} operation - can
      * only range devices which are part of an ongoing discovery session.
      *
@@ -230,7 +227,7 @@
      *                 {@link android.net.wifi.RttManager.RttParams#bssid} member must be set to
      *                 a peer ID - not to a MAC address.
      * @param listener The listener to receive the results of the ranging session.
-     * @hide PROPOSED_AWARE_SYSTEM_API
+     * @hide
      * [TODO: b/28847998 - track RTT API & visilibity]
      */
     public void startRanging(RttManager.RttParams[] params, RttManager.RttListener listener) {
@@ -265,9 +262,9 @@
      * and a Publisher is a RESPONDER.
      *
      * @param peerHandle The peer's handle obtained through
-     * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
      * byte[], java.util.List)} or
-     * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+     * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
      * byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request
      *                   from only that peer. A RESPONDER may specified a null - indicating that
      *                   it will accept connection requests from any device.
@@ -283,7 +280,7 @@
      * android.net.ConnectivityManager.NetworkCallback)}
      * [or other varieties of that API].
      */
-    public String createNetworkSpecifier(@Nullable WifiAwareManager.PeerHandle peerHandle,
+    public String createNetworkSpecifier(@Nullable PeerHandle peerHandle,
             @Nullable byte[] token) {
         if (mTerminated) {
             Log.w(TAG, "createNetworkSpecifier: called on terminated session");
@@ -295,7 +292,7 @@
                 return null;
             }
 
-            int role = this instanceof WifiAwareSubscribeDiscoverySession
+            int role = this instanceof SubscribeDiscoverySession
                     ? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
                     : WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
 
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
new file mode 100644
index 0000000..33da182
--- /dev/null
+++ b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.aware;
+
+import android.annotation.NonNull;
+
+import java.util.List;
+
+/**
+ * Base class for Aware session events callbacks. Should be extended by
+ * applications wanting notifications. The callbacks are set when a
+ * publish or subscribe session is created using
+ * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback,
+ * android.os.Handler)} or
+ * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback,
+ * android.os.Handler)}.
+ * <p>
+ * A single callback is set at session creation - it cannot be replaced.
+ */
+public class DiscoverySessionCallback {
+    /**
+     * Called when a publish operation is started successfully in response to a
+     * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback,
+     * android.os.Handler)} operation.
+     *
+     * @param session The {@link PublishDiscoverySession} used to control the
+     *            discovery session.
+     */
+    public void onPublishStarted(@NonNull PublishDiscoverySession session) {
+        /* empty */
+    }
+
+    /**
+     * Called when a subscribe operation is started successfully in response to a
+     * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback,
+     * android.os.Handler)} operation.
+     *
+     * @param session The {@link SubscribeDiscoverySession} used to control the
+     *            discovery session.
+     */
+    public void onSubscribeStarted(@NonNull SubscribeDiscoverySession session) {
+        /* empty */
+    }
+
+    /**
+     * Called when a publish or subscribe discovery session configuration update request
+     * succeeds. Called in response to
+     * {@link PublishDiscoverySession#updatePublish(PublishConfig)} or
+     * {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
+     */
+    public void onSessionConfigUpdated() {
+        /* empty */
+    }
+
+    /**
+     * Called when a publish or subscribe discovery session cannot be created:
+     * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback,
+     * android.os.Handler)} or
+     * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback,
+     * android.os.Handler)}, or when a configuration update fails:
+     * {@link PublishDiscoverySession#updatePublish(PublishConfig)} or
+     * {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
+     * <p>
+     *     For discovery session updates failure leaves the session running with its previous
+     *     configuration - the discovery session is not terminated.
+     */
+    public void onSessionConfigFailed() {
+        /* empty */
+    }
+
+    /**
+     * Called when a discovery session (publish or subscribe) terminates. Termination may be due
+     * to user-request (either directly through {@link DiscoverySession#destroy()} or
+     * application-specified expiration, e.g. {@link PublishConfig.Builder#setPublishCount(int)}
+     * or {@link SubscribeConfig.Builder#setTtlSec(int)}).
+     */
+    public void onSessionTerminated() {
+        /* empty */
+    }
+
+    /**
+     * Called when a discovery (publish or subscribe) operation results in a
+     * service discovery.
+     *
+     * @param peerHandle An opaque handle to the peer matching our discovery operation.
+     * @param serviceSpecificInfo The service specific information (arbitrary
+     *            byte array) provided by the peer as part of its discovery
+     *            configuration.
+     * @param matchFilter The filter which resulted in this service discovery.
+     */
+    public void onServiceDiscovered(PeerHandle peerHandle,
+            byte[] serviceSpecificInfo, List<byte[]> matchFilter) {
+        /* empty */
+    }
+
+    /**
+     * Called in response to
+     * {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])}
+     * when a message is transmitted successfully - i.e. when it was received successfully by the
+     * peer (corresponds to an ACK being received).
+     * <p>
+     * Note that either this callback or
+     * {@link DiscoverySessionCallback#onMessageSendFailed(int)} will be
+     * received - never both.
+     *
+     * @param messageId The arbitrary message ID specified when sending the message.
+     */
+    public void onMessageSendSucceeded(@SuppressWarnings("unused") int messageId) {
+        /* empty */
+    }
+
+    /**
+     * Called when message transmission fails - when no ACK is received from the peer.
+     * Retries when ACKs are not received are done by hardware, MAC, and in the Aware stack (using
+     * the {@link DiscoverySession#sendMessage(PeerHandle, int,
+     * byte[], int)} method) - this event is received after all retries are exhausted.
+     * <p>
+     * Note that either this callback or
+     * {@link DiscoverySessionCallback#onMessageSendSucceeded(int)} will be received
+     * - never both.
+     *
+     * @param messageId The arbitrary message ID specified when sending the message.
+     */
+    public void onMessageSendFailed(@SuppressWarnings("unused") int messageId) {
+        /* empty */
+    }
+
+    /**
+     * Called when a message is received from a discovery session peer - in response to the
+     * peer's {@link DiscoverySession#sendMessage(PeerHandle, int,
+     * byte[])} or {@link DiscoverySession#sendMessage(PeerHandle,
+     * int, byte[], int)}.
+     *
+     * @param peerHandle An opaque handle to the peer matching our discovery operation.
+     * @param message A byte array containing the message.
+     */
+    public void onMessageReceived(PeerHandle peerHandle, byte[] message) {
+        /* empty */
+    }
+}
diff --git a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
index 9c92807..794c142 100644
--- a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
+++ b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
@@ -23,7 +23,7 @@
 import android.net.wifi.aware.IWifiAwareEventCallback;
 import android.net.wifi.aware.PublishConfig;
 import android.net.wifi.aware.SubscribeConfig;
-import android.net.wifi.aware.WifiAwareCharacteristics;
+import android.net.wifi.aware.Characteristics;
 import android.net.wifi.RttManager;
 
 /**
@@ -37,7 +37,7 @@
     void enableUsage();
     void disableUsage();
     boolean isUsageEnabled();
-    WifiAwareCharacteristics getCharacteristics();
+    Characteristics getCharacteristics();
 
     // client API
     void connect(in IBinder binder, in String callingPackage, in IWifiAwareEventCallback callback,
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareIdentityChangedListener.java b/wifi/java/android/net/wifi/aware/IdentityChangedListener.java
similarity index 95%
rename from wifi/java/android/net/wifi/aware/WifiAwareIdentityChangedListener.java
rename to wifi/java/android/net/wifi/aware/IdentityChangedListener.java
index e8f52cd4..cae8706 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareIdentityChangedListener.java
+++ b/wifi/java/android/net/wifi/aware/IdentityChangedListener.java
@@ -25,10 +25,8 @@
  * interface may also be useful if the application uses alternative (non-Aware) discovery but needs
  * to set up a Aware connection. The provided Aware discovery interface MAC address can then be used
  * in {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])}.
- *
- * @hide PROPOSED_AWARE_API
  */
-public class WifiAwareIdentityChangedListener {
+public class IdentityChangedListener {
     /**
      * @param mac The MAC address of the Aware discovery interface. The application must have the
      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} to get the actual MAC address,
diff --git a/wifi/java/android/net/wifi/aware/PeerHandle.java b/wifi/java/android/net/wifi/aware/PeerHandle.java
new file mode 100644
index 0000000..bbe9f54
--- /dev/null
+++ b/wifi/java/android/net/wifi/aware/PeerHandle.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.aware;
+
+/**
+ * Opaque object used to represent a Wi-Fi Aware peer. Obtained from discovery sessions in
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)}, used
+ * when sending messages e,g, {@link PublishDiscoverySession#sendMessage(PeerHandle, int, byte[])},
+ * or when configuring a network link to a peer, e.g.
+ * {@link PublishDiscoverySession#createNetworkSpecifier(PeerHandle, byte[])}.
+ */
+public class PeerHandle {
+    /** @hide */
+    public PeerHandle(int peerId) {
+        this.peerId = peerId;
+    }
+
+    /** @hide */
+    public int peerId;
+}
diff --git a/wifi/java/android/net/wifi/aware/PublishConfig.java b/wifi/java/android/net/wifi/aware/PublishConfig.java
index 3925bd7..a996844 100644
--- a/wifi/java/android/net/wifi/aware/PublishConfig.java
+++ b/wifi/java/android/net/wifi/aware/PublishConfig.java
@@ -33,11 +33,9 @@
 /**
  * Defines the configuration of a Aware publish session. Built using
  * {@link PublishConfig.Builder}. A publish session is created using
- * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
+ * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback,
  * android.os.Handler)} or updated using
- * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)}.
- *
- * @hide PROPOSED_AWARE_API
+ * {@link PublishDiscoverySession#updatePublish(PublishConfig)}.
  */
 public final class PublishConfig implements Parcelable {
     /** @hide */
@@ -184,7 +182,7 @@
      *
      * @hide
      */
-    public void assertValid(WifiAwareCharacteristics characteristics)
+    public void assertValid(Characteristics characteristics)
             throws IllegalArgumentException {
         WifiAwareUtils.validateServiceName(mServiceName);
 
@@ -322,12 +320,11 @@
          * Sets the number of times an unsolicited (configured using
          * {@link PublishConfig.Builder#setPublishType(int)}) publish session
          * will be broadcast. When the count is reached an event will be
-         * generated for {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)}
-         * with {@link WifiAwareDiscoverySessionCallback#TERMINATE_REASON_DONE} [unless
-         * {@link #setTerminateNotificationEnabled(boolean)} disables the callback].
+         * generated for {@link DiscoverySessionCallback#onSessionTerminated()}
+         * [unless {@link #setTerminateNotificationEnabled(boolean)} disables the callback].
          * <p>
          *     Optional. 0 by default - indicating the session doesn't terminate on its own.
-         *     Session will be terminated when {@link WifiAwareDiscoveryBaseSession#destroy()} is
+         *     Session will be terminated when {@link DiscoverySession#destroy()} is
          *     called.
          *
          * @param publishCount Number of publish packets to broadcast.
@@ -348,12 +345,11 @@
          * {@link PublishConfig.Builder#setPublishType(int)}) publish session
          * will be alive - broadcasting a packet. When the TTL is reached
          * an event will be generated for
-         * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} with
-         * {@link WifiAwareDiscoverySessionCallback#TERMINATE_REASON_DONE}  [unless
+         * {@link DiscoverySessionCallback#onSessionTerminated()} [unless
          * {@link #setTerminateNotificationEnabled(boolean)} disables the callback].
          * <p>
          *     Optional. 0 by default - indicating the session doesn't terminate on its own.
-         *     Session will be terminated when {@link WifiAwareDiscoveryBaseSession#destroy()} is
+         *     Session will be terminated when {@link DiscoverySession#destroy()} is
          *     called.
          *
          * @param ttlSec Lifetime of a publish session in seconds.
@@ -371,7 +367,7 @@
 
         /**
          * Configure whether a publish terminate notification
-         * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} is reported
+         * {@link DiscoverySessionCallback#onSessionTerminated()} is reported
          * back to the callback.
          *
          * @param enable If true the terminate callback will be called when the
diff --git a/wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java b/wifi/java/android/net/wifi/aware/PublishDiscoverySession.java
similarity index 69%
rename from wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java
rename to wifi/java/android/net/wifi/aware/PublishDiscoverySession.java
index 68786d1..1c99c87 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/PublishDiscoverySession.java
@@ -21,32 +21,30 @@
 
 /**
  * A class representing a Aware publish session. Created when
- * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
+ * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback,
  * android.os.Handler)} is called and a discovery session is created and returned in
- * {@link WifiAwareDiscoverySessionCallback#onPublishStarted(WifiAwarePublishDiscoverySession)}. See
- * baseline functionality of all discovery sessions in {@link WifiAwareDiscoveryBaseSession}. This
+ * {@link DiscoverySessionCallback#onPublishStarted(PublishDiscoverySession)}. See
+ * baseline functionality of all discovery sessions in {@link DiscoverySession}. This
  * object allows updating an existing/running publish discovery session using
  * {@link #updatePublish(PublishConfig)}.
- *
- * @hide PROPOSED_AWARE_API
  */
-public class WifiAwarePublishDiscoverySession extends WifiAwareDiscoveryBaseSession {
-    private static final String TAG = "WifiAwarePublishDiscSsn";
+public class PublishDiscoverySession extends DiscoverySession {
+    private static final String TAG = "PublishDiscoverySession";
 
     /** @hide */
-    public WifiAwarePublishDiscoverySession(WifiAwareManager manager, int clientId, int sessionId) {
+    public PublishDiscoverySession(WifiAwareManager manager, int clientId, int sessionId) {
         super(manager, clientId, sessionId);
     }
 
     /**
      * Re-configure the currently active publish session. The
-     * {@link WifiAwareDiscoverySessionCallback} is not replaced - the same listener used
+     * {@link DiscoverySessionCallback} is not replaced - the same listener used
      * at creation is still used. The results of the configuration are returned using
-     * {@link WifiAwareDiscoverySessionCallback}:
+     * {@link DiscoverySessionCallback}:
      * <ul>
-     *     <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigUpdated()}: configuration
+     *     <li>{@link DiscoverySessionCallback#onSessionConfigUpdated()}: configuration
      *     update succeeded.
-     *     <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigFailed()}: configuration
+     *     <li>{@link DiscoverySessionCallback#onSessionConfigFailed()}: configuration
      *     update failed. The publish discovery session is still running using its previous
      *     configuration (i.e. update failure does not terminate the session).
      * </ul>
diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
index 0fe69a8..3397c4b 100644
--- a/wifi/java/android/net/wifi/aware/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
@@ -33,11 +33,9 @@
 /**
  * Defines the configuration of a Aware subscribe session. Built using
  * {@link SubscribeConfig.Builder}. Subscribe is done using
- * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
+ * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback,
  * android.os.Handler)} or
- * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
- *
- * @hide PROPOSED_AWARE_API
+ * {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
  */
 public final class SubscribeConfig implements Parcelable {
     /** @hide */
@@ -212,7 +210,7 @@
      *
      * @hide
      */
-    public void assertValid(WifiAwareCharacteristics characteristics)
+    public void assertValid(Characteristics characteristics)
             throws IllegalArgumentException {
         WifiAwareUtils.validateServiceName(mServiceName);
 
@@ -355,11 +353,10 @@
          * Sets the number of times an active (
          * {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe session
          * will broadcast. When the count is reached an event will be
-         * generated for {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)}
-         * with {@link WifiAwareDiscoverySessionCallback#TERMINATE_REASON_DONE}.
+         * generated for {@link DiscoverySessionCallback#onSessionTerminated()}.
          * <p>
          *     Optional. 0 by default - indicating the session doesn't terminate on its own.
-         *     Session will be terminated when {@link WifiAwareDiscoveryBaseSession#destroy()} is
+         *     Session will be terminated when {@link DiscoverySession#destroy()} is
          *     called.
          *
          * @param subscribeCount Number of subscribe packets to broadcast.
@@ -380,11 +377,10 @@
          * {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe session
          * will be alive - i.e. broadcasting a packet. When the TTL is reached
          * an event will be generated for
-         * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} with
-         * {@link WifiAwareDiscoverySessionCallback#TERMINATE_REASON_DONE}.
+         * {@link DiscoverySessionCallback#onSessionTerminated()}.
          * <p>
          *     Optional. 0 by default - indicating the session doesn't terminate on its own.
-         *     Session will be terminated when {@link WifiAwareDiscoveryBaseSession#destroy()} is
+         *     Session will be terminated when {@link DiscoverySession#destroy()} is
          *     called.
          *
          * @param ttlSec Lifetime of a subscribe session in seconds.
@@ -404,8 +400,8 @@
          * Sets the match style of the subscription - how are matches from a
          * single match session (corresponding to the same publish action on the
          * peer) reported to the host (using the
-         * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
-         * byte[], List)}). The options are: only report the first match and ignore the rest
+         * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[],
+         * java.util.List)}). The options are: only report the first match and ignore the rest
          * {@link SubscribeConfig#MATCH_STYLE_FIRST_ONLY} or report every single
          * match {@link SubscribeConfig#MATCH_STYLE_ALL} (the default).
          *
@@ -424,7 +420,7 @@
 
         /**
          * Configure whether a subscribe terminate notification
-         * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} is reported
+         * {@link DiscoverySessionCallback#onSessionTerminated()} is reported
          * back to the callback.
          *
          * @param enable If true the terminate callback will be called when the
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java b/wifi/java/android/net/wifi/aware/SubscribeDiscoverySession.java
similarity index 74%
rename from wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java
rename to wifi/java/android/net/wifi/aware/SubscribeDiscoverySession.java
index a0ec809..ca88a90 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/SubscribeDiscoverySession.java
@@ -22,35 +22,33 @@
 /**
  * A class representing a Aware subscribe session. Created when
  * {@link WifiAwareSession#subscribe(SubscribeConfig,
- * WifiAwareDiscoverySessionCallback, android.os.Handler)}
+ * DiscoverySessionCallback, android.os.Handler)}
  * is called and a discovery session is created and returned in
- * {@link WifiAwareDiscoverySessionCallback#onSubscribeStarted(WifiAwareSubscribeDiscoverySession)}.
- * See baseline functionality of all discovery sessions in {@link WifiAwareDiscoveryBaseSession}.
+ * {@link DiscoverySessionCallback#onSubscribeStarted(SubscribeDiscoverySession)}.
+ * See baseline functionality of all discovery sessions in {@link DiscoverySession}.
  * This object allows updating an existing/running subscribe discovery session using
  * {@link #updateSubscribe(SubscribeConfig)}.
- *
- * @hide PROPOSED_AWARE_API
  */
-public class WifiAwareSubscribeDiscoverySession extends WifiAwareDiscoveryBaseSession {
-    private static final String TAG = "WifiAwareSubsDiscSsn";
+public class SubscribeDiscoverySession extends DiscoverySession {
+    private static final String TAG = "SubscribeDiscSession";
 
     /**
      * {@hide}
      */
-    public WifiAwareSubscribeDiscoverySession(WifiAwareManager manager, int clientId,
+    public SubscribeDiscoverySession(WifiAwareManager manager, int clientId,
             int sessionId) {
         super(manager, clientId, sessionId);
     }
 
     /**
      * Re-configure the currently active subscribe session. The
-     * {@link WifiAwareDiscoverySessionCallback} is not replaced - the same listener used
+     * {@link DiscoverySessionCallback} is not replaced - the same listener used
      * at creation is still used. The results of the configuration are returned using
-     * {@link WifiAwareDiscoverySessionCallback}:
+     * {@link DiscoverySessionCallback}:
      * <ul>
-     *     <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigUpdated()}: configuration
+     *     <li>{@link DiscoverySessionCallback#onSessionConfigUpdated()}: configuration
      *     update succeeded.
-     *     <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigFailed()}: configuration
+     *     <li>{@link DiscoverySessionCallback#onSessionConfigFailed()}: configuration
      *     update failed. The subscribe discovery session is still running using its previous
      *     configuration (i.e. update failure does not terminate the session).
      * </ul>
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
deleted file mode 100644
index fdf0d01..0000000
--- a/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.aware;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-
-/**
- * Base class for Aware session events callbacks. Should be extended by
- * applications wanting notifications. The callbacks are set when a
- * publish or subscribe session is created using
- * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
- * android.os.Handler)} or
- * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
- * android.os.Handler)}.
- * <p>
- * A single callback is set at session creation - it cannot be replaced.
- *
- * @hide PROPOSED_AWARE_API
- */
-public class WifiAwareDiscoverySessionCallback {
-    /** @hide */
-    @IntDef({
-            TERMINATE_REASON_DONE, TERMINATE_REASON_FAIL })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface SessionTerminateCodes {
-    }
-
-    /**
-     * Indicates that publish or subscribe session is done - all the
-     * requested operations (per {@link PublishConfig} or
-     * {@link SubscribeConfig}) have been executed. Failure reason flag for
-     * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} callback.
-     */
-    public static final int TERMINATE_REASON_DONE = 100;
-
-    /**
-     * Indicates that publish or subscribe session is terminated due to a
-     * failure.
-     * Failure reason flag for
-     * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} callback.
-     */
-    public static final int TERMINATE_REASON_FAIL = 101;
-
-    /**
-     * Called when a publish operation is started successfully in response to a
-     * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
-     * android.os.Handler)} operation.
-     *
-     * @param session The {@link WifiAwarePublishDiscoverySession} used to control the
-     *            discovery session.
-     */
-    public void onPublishStarted(@NonNull WifiAwarePublishDiscoverySession session) {
-        /* empty */
-    }
-
-    /**
-     * Called when a subscribe operation is started successfully in response to a
-     * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
-     * android.os.Handler)} operation.
-     *
-     * @param session The {@link WifiAwareSubscribeDiscoverySession} used to control the
-     *            discovery session.
-     */
-    public void onSubscribeStarted(@NonNull WifiAwareSubscribeDiscoverySession session) {
-        /* empty */
-    }
-
-    /**
-     * Called when a publish or subscribe discovery session configuration update request
-     * succeeds. Called in response to
-     * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)} or
-     * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
-     */
-    public void onSessionConfigUpdated() {
-        /* empty */
-    }
-
-    /**
-     * Called when a publish or subscribe discovery session cannot be created:
-     * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
-     * android.os.Handler)} or
-     * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
-     * android.os.Handler)}, or when a configuration update fails:
-     * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)} or
-     * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
-     * <p>
-     *     For discovery session updates failure leaves the session running with its previous
-     *     configuration - the discovery session is not terminated.
-     */
-    public void onSessionConfigFailed() {
-        /* empty */
-    }
-
-    /**
-     * Called when a discovery session (publish or subscribe) terminates. Termination may be due
-     * to user-request (either directly through {@link WifiAwareDiscoveryBaseSession#destroy()} or
-     * application-specified expiration, e.g. {@link PublishConfig.Builder#setPublishCount(int)}
-     * or {@link SubscribeConfig.Builder#setTtlSec(int)}) or due to a failure.
-     *
-     * @param reason The termination reason using
-     *            {@code WifiAwareDiscoverySessionCallback.TERMINATE_*} codes.
-     */
-    public void onSessionTerminated(@SessionTerminateCodes int reason) {
-        /* empty */
-    }
-
-    /**
-     * Called when a discovery (publish or subscribe) operation results in a
-     * service discovery.
-     *
-     * @param peerHandle An opaque handle to the peer matching our discovery operation.
-     * @param serviceSpecificInfo The service specific information (arbitrary
-     *            byte array) provided by the peer as part of its discovery
-     *            configuration.
-     * @param matchFilter The filter which resulted in this service discovery.
-     */
-    public void onServiceDiscovered(WifiAwareManager.PeerHandle peerHandle,
-            byte[] serviceSpecificInfo, List<byte[]> matchFilter) {
-        /* empty */
-    }
-
-    /**
-     * Called in response to
-     * {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int, byte[])}
-     * when a message is transmitted successfully - i.e. when it was received successfully by the
-     * peer (corresponds to an ACK being received).
-     * <p>
-     * Note that either this callback or
-     * {@link WifiAwareDiscoverySessionCallback#onMessageSendFailed(int)} will be
-     * received - never both.
-     *
-     * @param messageId The arbitrary message ID specified when sending the message.
-     */
-    public void onMessageSendSucceeded(@SuppressWarnings("unused") int messageId) {
-        /* empty */
-    }
-
-    /**
-     * Called when message transmission fails - when no ACK is received from the peer.
-     * Retries when ACKs are not received are done by hardware, MAC, and in the Aware stack (using
-     * the {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int,
-     * byte[], int)} method) - this event is received after all retries are exhausted.
-     * <p>
-     * Note that either this callback or
-     * {@link WifiAwareDiscoverySessionCallback#onMessageSendSucceeded(int)} will be received
-     * - never both.
-     *
-     * @param messageId The arbitrary message ID specified when sending the message.
-     */
-    public void onMessageSendFailed(@SuppressWarnings("unused") int messageId) {
-        /* empty */
-    }
-
-    /**
-     * Called when a message is received from a discovery session peer - in response to the
-     * peer's {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int,
-     * byte[])} or {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle,
-     * int, byte[], int)}.
-     *
-     * @param peerHandle An opaque handle to the peer matching our discovery operation.
-     * @param message A byte array containing the message.
-     */
-    public void onMessageReceived(WifiAwareManager.PeerHandle peerHandle, byte[] message) {
-        /* empty */
-    }
-}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 029794d..043925ed 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -58,14 +58,14 @@
  * The class provides access to:
  * <ul>
  * <li>Initialize a Aware cluster (peer-to-peer synchronization). Refer to
- * {@link #attach(WifiAwareAttachCallback, Handler)}.
+ * {@link #attach(AttachCallback, Handler)}.
  * <li>Create discovery sessions (publish or subscribe sessions). Refer to
- * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback, Handler)} and
- * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback, Handler)}.
+ * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback, Handler)} and
+ * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback, Handler)}.
  * <li>Create a Aware network specifier to be used with
  * {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}
  * to set-up a Aware connection with a peer. Refer to
- * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])} and
+ * {@link DiscoverySession#createNetworkSpecifier(PeerHandle, byte[])} and
  * {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])}.
  * </ul>
  * <p>
@@ -75,37 +75,37 @@
  *     broadcast. Note that this broadcast is not sticky - you should register for it and then
  *     check the above API to avoid a race condition.
  * <p>
- *     An application must use {@link #attach(WifiAwareAttachCallback, Handler)} to initialize a
+ *     An application must use {@link #attach(AttachCallback, Handler)} to initialize a
  *     Aware cluster - before making any other Aware operation. Aware cluster membership is a
  *     device-wide operation - the API guarantees that the device is in a cluster or joins a
  *     Aware cluster (or starts one if none can be found). Information about attach success (or
- *     failure) are returned in callbacks of {@link WifiAwareAttachCallback}. Proceed with Aware
+ *     failure) are returned in callbacks of {@link AttachCallback}. Proceed with Aware
  *     discovery or connection setup only after receiving confirmation that Aware attach
- *     succeeded - {@link WifiAwareAttachCallback#onAttached(WifiAwareSession)}. When an
+ *     succeeded - {@link AttachCallback#onAttached(WifiAwareSession)}. When an
  *     application is finished using Aware it <b>must</b> use the
  *     {@link WifiAwareSession#destroy()} API to indicate to the Aware service that the device
  *     may detach from the Aware cluster. The device will actually disable Aware once the last
  *     application detaches.
  * <p>
  *     Once a Aware attach is confirmed use the
- *     {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback, Handler)}
+ *     {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback, Handler)}
  *     or
- *     {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
+ *     {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback,
  *     Handler)} to create publish or subscribe Aware discovery sessions. Events are called on the
- *     provided callback object {@link WifiAwareDiscoverySessionCallback}. Specifically, the
- *     {@link WifiAwareDiscoverySessionCallback#onPublishStarted(WifiAwarePublishDiscoverySession)}
+ *     provided callback object {@link DiscoverySessionCallback}. Specifically, the
+ *     {@link DiscoverySessionCallback#onPublishStarted(PublishDiscoverySession)}
  *     and
- *     {@link WifiAwareDiscoverySessionCallback#onSubscribeStarted(
- *     WifiAwareSubscribeDiscoverySession)}
- *     return {@link WifiAwarePublishDiscoverySession} and
- *     {@link WifiAwareSubscribeDiscoverySession}
+ *     {@link DiscoverySessionCallback#onSubscribeStarted(
+ *SubscribeDiscoverySession)}
+ *     return {@link PublishDiscoverySession} and
+ *     {@link SubscribeDiscoverySession}
  *     objects respectively on which additional session operations can be performed, e.g. updating
- *     the session {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)} and
- *     {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. Sessions can
+ *     the session {@link PublishDiscoverySession#updatePublish(PublishConfig)} and
+ *     {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. Sessions can
  *     also be used to send messages using the
- *     {@link WifiAwareDiscoveryBaseSession#sendMessage(PeerHandle, int, byte[])} APIs. When an
+ *     {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])} APIs. When an
  *     application is finished with a discovery session it <b>must</b> terminate it using the
- *     {@link WifiAwareDiscoveryBaseSession#destroy()} API.
+ *     {@link DiscoverySession#destroy()} API.
  * <p>
  *    Creating connections between Aware devices is managed by the standard
  *    {@link ConnectivityManager#requestNetwork(NetworkRequest,
@@ -116,10 +116,8 @@
  *        {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
  *        <li>{@link NetworkRequest.Builder#setNetworkSpecifier(String)} using
  *        {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])} or
- *        {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])}.
+ *        {@link DiscoverySession#createNetworkSpecifier(PeerHandle, byte[])}.
  *    </ul>
- *
- * @hide PROPOSED_AWARE_API
  */
 public class WifiAwareManager {
     private static final String TAG = "WifiAwareManager";
@@ -226,7 +224,7 @@
      * Connection creation role is that of INITIATOR. Used to create a network specifier string
      * when requesting a Aware network.
      *
-     * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])
+     * @see DiscoverySession#createNetworkSpecifier(PeerHandle, byte[])
      * @see WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])
      */
     public static final int WIFI_AWARE_DATA_PATH_ROLE_INITIATOR = 0;
@@ -235,7 +233,7 @@
      * Connection creation role is that of RESPONDER. Used to create a network specifier string
      * when requesting a Aware network.
      *
-     * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])
+     * @see DiscoverySession#createNetworkSpecifier(PeerHandle, byte[])
      * @see WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])
      */
     public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1;
@@ -305,9 +303,8 @@
      * limitations on configurations, e.g. the maximum service name length.
      *
      * @return An object specifying configuration limitations of Aware.
-     * @hide PROPOSED_AWARE_API
      */
-    public WifiAwareCharacteristics getCharacteristics() {
+    public Characteristics getCharacteristics() {
         try {
             return mService.getCharacteristics();
         } catch (RemoteException e) {
@@ -328,12 +325,12 @@
      * attachCallback}.
      *
      * @param attachCallback A callback for attach events, extended from
-     * {@link WifiAwareAttachCallback}.
+     * {@link AttachCallback}.
      * @param handler The Handler on whose thread to execute the callbacks of the {@code
      * attachCallback} object. If a null is provided then the application's main thread will be
      *                used.
      */
-    public void attach(@NonNull WifiAwareAttachCallback attachCallback, @Nullable Handler handler) {
+    public void attach(@NonNull AttachCallback attachCallback, @Nullable Handler handler) {
         attach(handler, null, attachCallback, null);
     }
 
@@ -353,28 +350,28 @@
      * on startup and whenever it is updated (it is randomized at regular intervals for privacy).
      * The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
      * permission to execute this attach request. Otherwise, use the
-     * {@link #attach(WifiAwareAttachCallback, Handler)} version. Note that aside from permission
+     * {@link #attach(AttachCallback, Handler)} version. Note that aside from permission
      * requirements this listener will wake up the host at regular intervals causing higher power
      * consumption, do not use it unless the information is necessary (e.g. for OOB discovery).
      *
      * @param attachCallback A callback for attach events, extended from
-     * {@link WifiAwareAttachCallback}.
+     * {@link AttachCallback}.
      * @param identityChangedListener A listener for changed identity, extended from
-     * {@link WifiAwareIdentityChangedListener}.
+     * {@link IdentityChangedListener}.
      * @param handler The Handler on whose thread to execute the callbacks of the {@code
      * attachCallback} and {@code identityChangedListener} objects. If a null is provided then the
      *                application's main thread will be used.
      */
-    public void attach(@NonNull WifiAwareAttachCallback attachCallback,
-            @NonNull WifiAwareIdentityChangedListener identityChangedListener,
+    public void attach(@NonNull AttachCallback attachCallback,
+            @NonNull IdentityChangedListener identityChangedListener,
             @Nullable Handler handler) {
         attach(handler, null, attachCallback, identityChangedListener);
     }
 
     /** @hide */
     public void attach(Handler handler, ConfigRequest configRequest,
-            WifiAwareAttachCallback attachCallback,
-            WifiAwareIdentityChangedListener identityChangedListener) {
+            AttachCallback attachCallback,
+            IdentityChangedListener identityChangedListener) {
         if (VDBG) {
             Log.v(TAG, "attach(): handler=" + handler + ", callback=" + attachCallback
                     + ", configRequest=" + configRequest + ", identityChangedListener="
@@ -409,7 +406,7 @@
 
     /** @hide */
     public void publish(int clientId, Looper looper, PublishConfig publishConfig,
-            WifiAwareDiscoverySessionCallback callback) {
+            DiscoverySessionCallback callback) {
         if (VDBG) Log.v(TAG, "publish(): clientId=" + clientId + ", config=" + publishConfig);
 
         try {
@@ -437,7 +434,7 @@
 
     /** @hide */
     public void subscribe(int clientId, Looper looper, SubscribeConfig subscribeConfig,
-            WifiAwareDiscoverySessionCallback callback) {
+            DiscoverySessionCallback callback) {
         if (VDBG) {
             if (VDBG) {
                 Log.v(TAG,
@@ -672,14 +669,14 @@
         }
 
         /**
-         * Constructs a {@link WifiAwareAttachCallback} using the specified looper.
+         * Constructs a {@link AttachCallback} using the specified looper.
          * All callbacks will delivered on the thread of the specified looper.
          *
          * @param looper The looper on which to execute the callbacks.
          */
         WifiAwareEventCallbackProxy(WifiAwareManager mgr, Looper looper, Binder binder,
-                final WifiAwareAttachCallback attachCallback,
-                final WifiAwareIdentityChangedListener identityChangedListener) {
+                final AttachCallback attachCallback,
+                final IdentityChangedListener identityChangedListener) {
             mAwareManager = new WeakReference<>(mgr);
             mLooper = looper;
             mBinder = binder;
@@ -828,14 +825,14 @@
 
         private final WeakReference<WifiAwareManager> mAwareManager;
         private final boolean mIsPublish;
-        private final WifiAwareDiscoverySessionCallback mOriginalCallback;
+        private final DiscoverySessionCallback mOriginalCallback;
         private final int mClientId;
 
         private final Handler mHandler;
-        private WifiAwareDiscoveryBaseSession mSession;
+        private DiscoverySession mSession;
 
         WifiAwareDiscoverySessionCallbackProxy(WifiAwareManager mgr, Looper looper,
-                boolean isPublish, WifiAwareDiscoverySessionCallback originalCallback,
+                boolean isPublish, DiscoverySessionCallback originalCallback,
                 int clientId) {
             mAwareManager = new WeakReference<>(mgr);
             mIsPublish = isPublish;
@@ -1006,13 +1003,13 @@
             }
 
             if (mIsPublish) {
-                WifiAwarePublishDiscoverySession session = new WifiAwarePublishDiscoverySession(mgr,
+                PublishDiscoverySession session = new PublishDiscoverySession(mgr,
                         mClientId, sessionId);
                 mSession = session;
                 mOriginalCallback.onPublishStarted(session);
             } else {
-                WifiAwareSubscribeDiscoverySession
-                        session = new WifiAwareSubscribeDiscoverySession(mgr, mClientId, sessionId);
+                SubscribeDiscoverySession
+                        session = new SubscribeDiscoverySession(mgr, mClientId, sessionId);
                 mSession = session;
                 mOriginalCallback.onSubscribeStarted(session);
             }
@@ -1027,18 +1024,7 @@
                 Log.w(TAG, "Proxy: onSessionTerminated called but mSession is null!?");
             }
             mAwareManager.clear();
-            mOriginalCallback.onSessionTerminated(reason);
+            mOriginalCallback.onSessionTerminated();
         }
     }
-
-    /** @hide PROPOSED_AWARE_API */
-    public static class PeerHandle {
-        /** @hide */
-        public PeerHandle(int peerId) {
-            this.peerId = peerId;
-        }
-
-        /** @hide */
-        public int peerId;
-    }
 }
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index 005895a..8696920 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -30,8 +30,6 @@
 /**
  * This class represents a Wi-Fi Aware session - an attachment to the Wi-Fi Aware service through
  * which the app can execute discovery operations.
- *
- * @hide PROPOSED_AWARE_API
  */
 public class WifiAwareSession {
     private static final String TAG = "WifiAwareSession";
@@ -65,7 +63,7 @@
      * session-wide destroy.
      * <p>
      * An application may re-attach after a destroy using
-     * {@link WifiAwareManager#attach(WifiAwareAttachCallback, Handler)} .
+     * {@link WifiAwareManager#attach(AttachCallback, Handler)} .
      */
     public void destroy() {
         WifiAwareManager mgr = mMgr.get();
@@ -95,22 +93,22 @@
     /**
      * Issue a request to the Aware service to create a new Aware publish discovery session, using
      * the specified {@code publishConfig} configuration. The results of the publish operation
-     * are routed to the callbacks of {@link WifiAwareDiscoverySessionCallback}:
+     * are routed to the callbacks of {@link DiscoverySessionCallback}:
      * <ul>
      *     <li>
-     *     {@link WifiAwareDiscoverySessionCallback#onPublishStarted(
-     *     WifiAwarePublishDiscoverySession)}
+     *     {@link DiscoverySessionCallback#onPublishStarted(
+     *PublishDiscoverySession)}
      *     is called when the publish session is created and provides a handle to the session.
      *     Further operations on the publish session can be executed on that object.
-     *     <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigFailed()} is called if the
+     *     <li>{@link DiscoverySessionCallback#onSessionConfigFailed()} is called if the
      *     publish operation failed.
      * </ul>
      * <p>
      * Other results of the publish session operations will also be routed to callbacks
      * on the {@code callback} object. The resulting publish session can be modified using
-     * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)}.
+     * {@link PublishDiscoverySession#updatePublish(PublishConfig)}.
      * <p>
-     *      An application must use the {@link WifiAwareDiscoveryBaseSession#destroy()} to
+     *      An application must use the {@link DiscoverySession#destroy()} to
      *      terminate the publish discovery session once it isn't needed. This will free
      *      resources as well terminate any on-air transmissions.
      * <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
@@ -118,13 +116,13 @@
      *
      * @param publishConfig The {@link PublishConfig} specifying the
      *            configuration of the requested publish session.
-     * @param callback A {@link WifiAwareDiscoverySessionCallback} derived object to be used for
+     * @param callback A {@link DiscoverySessionCallback} derived object to be used for
      *                 session event callbacks.
      * @param handler The Handler on whose thread to execute the callbacks of the {@code
      * callback} object. If a null is provided then the application's main thread will be used.
      */
     public void publish(@NonNull PublishConfig publishConfig,
-            @NonNull WifiAwareDiscoverySessionCallback callback, @Nullable Handler handler) {
+            @NonNull DiscoverySessionCallback callback, @Nullable Handler handler) {
         WifiAwareManager mgr = mMgr.get();
         if (mgr == null) {
             Log.e(TAG, "publish: called post GC on WifiAwareManager");
@@ -141,22 +139,22 @@
     /**
      * Issue a request to the Aware service to create a new Aware subscribe discovery session, using
      * the specified {@code subscribeConfig} configuration. The results of the subscribe
-     * operation are routed to the callbacks of {@link WifiAwareDiscoverySessionCallback}:
+     * operation are routed to the callbacks of {@link DiscoverySessionCallback}:
      * <ul>
      *     <li>
-     *  {@link WifiAwareDiscoverySessionCallback#onSubscribeStarted(
-     *  WifiAwareSubscribeDiscoverySession)}
+     *  {@link DiscoverySessionCallback#onSubscribeStarted(
+     *SubscribeDiscoverySession)}
      *     is called when the subscribe session is created and provides a handle to the session.
      *     Further operations on the subscribe session can be executed on that object.
-     *     <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigFailed()} is called if the
+     *     <li>{@link DiscoverySessionCallback#onSessionConfigFailed()} is called if the
      *     subscribe operation failed.
      * </ul>
      * <p>
      * Other results of the subscribe session operations will also be routed to callbacks
      * on the {@code callback} object. The resulting subscribe session can be modified using
-     * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
+     * {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
      * <p>
-     *      An application must use the {@link WifiAwareDiscoveryBaseSession#destroy()} to
+     *      An application must use the {@link DiscoverySession#destroy()} to
      *      terminate the subscribe discovery session once it isn't needed. This will free
      *      resources as well terminate any on-air transmissions.
      * <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
@@ -164,13 +162,13 @@
      *
      * @param subscribeConfig The {@link SubscribeConfig} specifying the
      *            configuration of the requested subscribe session.
-     * @param callback A {@link WifiAwareDiscoverySessionCallback} derived object to be used for
+     * @param callback A {@link DiscoverySessionCallback} derived object to be used for
      *                 session event callbacks.
      * @param handler The Handler on whose thread to execute the callbacks of the {@code
      * callback} object. If a null is provided then the application's main thread will be used.
      */
     public void subscribe(@NonNull SubscribeConfig subscribeConfig,
-            @NonNull WifiAwareDiscoverySessionCallback callback, @Nullable Handler handler) {
+            @NonNull DiscoverySessionCallback callback, @Nullable Handler handler) {
         WifiAwareManager mgr = mMgr.get();
         if (mgr == null) {
             Log.e(TAG, "publish: called post GC on WifiAwareManager");
@@ -193,7 +191,7 @@
      *     This API is targeted for applications which can obtain the peer MAC address using OOB
      *     (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
      *     when using Aware discovery use the alternative network specifier method -
-     *     {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(WifiAwareManager.PeerHandle,
+     *     {@link DiscoverySession#createNetworkSpecifier(PeerHandle,
      *     byte[])}.
      *
      * @param role  The role of this device:
diff --git a/wifi/java/android/net/wifi/aware/package.html b/wifi/java/android/net/wifi/aware/package.html
index 1a990d8..d5d962f6 100644
--- a/wifi/java/android/net/wifi/aware/package.html
+++ b/wifi/java/android/net/wifi/aware/package.html
@@ -23,7 +23,7 @@
     If your application only works with Wi-Fi Aware (i.e. it should only be installed on devices which
     support Wi-Fi Aware), declare so with a <a
             href="{@docRoot}guide/topics/manifest/uses-feature-element.html">
-        {@code &lt;uses-feature&gt;}</a>
+        {@code <uses-feature>}</a>
     element in the manifest file:</p>
 <pre>
 &lt;manifest ...>
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 24c0127..a396d87 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -67,19 +67,19 @@
     public Context mockContext;
 
     @Mock
-    public WifiAwareAttachCallback mockCallback;
+    public AttachCallback mockCallback;
 
     @Mock
-    public WifiAwareDiscoverySessionCallback mockSessionCallback;
+    public DiscoverySessionCallback mockSessionCallback;
 
     @Mock
     public IWifiAwareManager mockAwareService;
 
     @Mock
-    public WifiAwarePublishDiscoverySession mockPublishSession;
+    public PublishDiscoverySession mockPublishSession;
 
     @Mock
-    public WifiAwareSubscribeDiscoverySession mockSubscribeSession;
+    public SubscribeDiscoverySession mockSubscribeSession;
 
     @Mock
     public RttManager.RttListener mockRttListener;
@@ -276,7 +276,7 @@
         final int sessionId = 123;
         final ConfigRequest configRequest = new ConfigRequest.Builder().build();
         final PublishConfig publishConfig = new PublishConfig.Builder().build();
-        final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(873);
+        final PeerHandle peerHandle = new PeerHandle(873);
         final String string1 = "hey from here...";
         final byte[] matchFilter = { 1, 12, 2, 31, 32 };
         final int messageId = 2123;
@@ -290,10 +290,9 @@
                 .forClass(IWifiAwareEventCallback.class);
         ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
                 .forClass(IWifiAwareDiscoverySessionCallback.class);
-        ArgumentCaptor<WifiAwarePublishDiscoverySession> publishSession = ArgumentCaptor
-                .forClass(WifiAwarePublishDiscoverySession.class);
-        ArgumentCaptor<WifiAwareManager.PeerHandle> peerIdCaptor = ArgumentCaptor.forClass(
-                WifiAwareManager.PeerHandle.class);
+        ArgumentCaptor<PublishDiscoverySession> publishSession = ArgumentCaptor
+                .forClass(PublishDiscoverySession.class);
+        ArgumentCaptor<PeerHandle> peerIdCaptor = ArgumentCaptor.forClass(PeerHandle.class);
         ArgumentCaptor<List<byte[]>> matchFilterCaptor = ArgumentCaptor.forClass(
                 (Class) List.class);
 
@@ -377,7 +376,6 @@
         final int sessionId = 123;
         final ConfigRequest configRequest = new ConfigRequest.Builder().build();
         final PublishConfig publishConfig = new PublishConfig.Builder().build();
-        final int reason = WifiAwareDiscoverySessionCallback.TERMINATE_REASON_DONE;
 
         InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
                 mockPublishSession);
@@ -387,8 +385,8 @@
                 .forClass(IWifiAwareEventCallback.class);
         ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
                 .forClass(IWifiAwareDiscoverySessionCallback.class);
-        ArgumentCaptor<WifiAwarePublishDiscoverySession> publishSession = ArgumentCaptor
-                .forClass(WifiAwarePublishDiscoverySession.class);
+        ArgumentCaptor<PublishDiscoverySession> publishSession = ArgumentCaptor
+                .forClass(PublishDiscoverySession.class);
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
@@ -404,10 +402,10 @@
         inOrder.verify(mockAwareService).publish(eq(clientId), eq(publishConfig),
                 sessionProxyCallback.capture());
         sessionProxyCallback.getValue().onSessionStarted(sessionId);
-        sessionProxyCallback.getValue().onSessionTerminated(reason);
+        sessionProxyCallback.getValue().onSessionTerminated(0);
         mMockLooper.dispatchAll();
         inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture());
-        inOrder.verify(mockSessionCallback).onSessionTerminated(reason);
+        inOrder.verify(mockSessionCallback).onSessionTerminated();
 
         // (3) failure when trying to update: NOP
         publishSession.getValue().updatePublish(publishConfig);
@@ -428,7 +426,7 @@
         final int sessionId = 123;
         final ConfigRequest configRequest = new ConfigRequest.Builder().build();
         final SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
-        final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(873);
+        final PeerHandle peerHandle = new PeerHandle(873);
         final String string1 = "hey from here...";
         final byte[] matchFilter = { 1, 12, 3, 31, 32 }; // bad data!
         final int messageId = 2123;
@@ -442,10 +440,9 @@
                 .forClass(IWifiAwareEventCallback.class);
         ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
                 .forClass(IWifiAwareDiscoverySessionCallback.class);
-        ArgumentCaptor<WifiAwareSubscribeDiscoverySession> subscribeSession = ArgumentCaptor
-                .forClass(WifiAwareSubscribeDiscoverySession.class);
-        ArgumentCaptor<WifiAwareManager.PeerHandle> peerIdCaptor = ArgumentCaptor.forClass(
-                WifiAwareManager.PeerHandle.class);
+        ArgumentCaptor<SubscribeDiscoverySession> subscribeSession = ArgumentCaptor
+                .forClass(SubscribeDiscoverySession.class);
+        ArgumentCaptor<PeerHandle> peerIdCaptor = ArgumentCaptor.forClass(PeerHandle.class);
 
         // (0) connect + success
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
@@ -516,7 +513,6 @@
         final int sessionId = 123;
         final ConfigRequest configRequest = new ConfigRequest.Builder().build();
         final SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
-        final int reason = WifiAwareDiscoverySessionCallback.TERMINATE_REASON_DONE;
 
         InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
                 mockSubscribeSession);
@@ -526,8 +522,8 @@
                 .forClass(IWifiAwareEventCallback.class);
         ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
                 .forClass(IWifiAwareDiscoverySessionCallback.class);
-        ArgumentCaptor<WifiAwareSubscribeDiscoverySession> subscribeSession = ArgumentCaptor
-                .forClass(WifiAwareSubscribeDiscoverySession.class);
+        ArgumentCaptor<SubscribeDiscoverySession> subscribeSession = ArgumentCaptor
+                .forClass(SubscribeDiscoverySession.class);
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
@@ -543,10 +539,10 @@
         inOrder.verify(mockAwareService).subscribe(eq(clientId), eq(subscribeConfig),
                 sessionProxyCallback.capture());
         sessionProxyCallback.getValue().onSessionStarted(sessionId);
-        sessionProxyCallback.getValue().onSessionTerminated(reason);
+        sessionProxyCallback.getValue().onSessionTerminated(0);
         mMockLooper.dispatchAll();
         inOrder.verify(mockSessionCallback).onSubscribeStarted(subscribeSession.capture());
-        inOrder.verify(mockSessionCallback).onSessionTerminated(reason);
+        inOrder.verify(mockSessionCallback).onSessionTerminated();
 
         // (3) failure when trying to update: NOP
         subscribeSession.getValue().updateSubscribe(subscribeConfig);
@@ -892,8 +888,8 @@
                 .forClass(IWifiAwareEventCallback.class);
         ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
                 .forClass(IWifiAwareDiscoverySessionCallback.class);
-        ArgumentCaptor<WifiAwarePublishDiscoverySession> publishSession = ArgumentCaptor
-                .forClass(WifiAwarePublishDiscoverySession.class);
+        ArgumentCaptor<PublishDiscoverySession> publishSession = ArgumentCaptor
+                .forClass(PublishDiscoverySession.class);
         ArgumentCaptor<RttManager.ParcelableRttParams> rttParamCaptor = ArgumentCaptor
                 .forClass(RttManager.ParcelableRttParams.class);
         ArgumentCaptor<RttManager.RttResult[]> rttResultsCaptor = ArgumentCaptor
@@ -953,7 +949,7 @@
     public void testNetworkSpecifierWithClient() throws Exception {
         final int clientId = 4565;
         final int sessionId = 123;
-        final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(123412);
+        final PeerHandle peerHandle = new PeerHandle(123412);
         final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
         final String token = "Some arbitrary token string - can really be anything";
         final ConfigRequest configRequest = new ConfigRequest.Builder().build();
@@ -967,8 +963,8 @@
                 .forClass(IWifiAwareEventCallback.class);
         ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
                 .forClass(IWifiAwareDiscoverySessionCallback.class);
-        ArgumentCaptor<WifiAwarePublishDiscoverySession> publishSession = ArgumentCaptor
-                .forClass(WifiAwarePublishDiscoverySession.class);
+        ArgumentCaptor<PublishDiscoverySession> publishSession = ArgumentCaptor
+                .forClass(PublishDiscoverySession.class);
 
         InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
                 mockPublishSession, mockRttListener);